mirror of
https://github.com/ppy/osu.git
synced 2026-06-02 00:20:40 +08:00
Compare commits
4 Commits
+1
-1
@@ -10,7 +10,7 @@
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.521.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.527.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
@@ -42,7 +43,7 @@ namespace osu.Game.Benchmarks
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
calculator = new OsuRuleset().CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
calculator = new OsuRuleset().CreateScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public partial class CatchModFlashlight : ModFlashlight<CatchHitObject>
|
||||
{
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||
|
||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
|
||||
{
|
||||
MinValue = 0.5f,
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
public override string Name => "Floating Fruits";
|
||||
public override string Acronym => "FF";
|
||||
public override LocalisableString Description => "The fruits are... floating?";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override IconUsage? Icon => OsuIcon.ModFloatingFruits;
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<CatchHitObject> drawableRuleset)
|
||||
|
||||
@@ -10,8 +10,6 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModHardRock : ModHardRock, IApplicableToBeatmapProcessor
|
||||
{
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||
|
||||
public void ApplyToBeatmapProcessor(IBeatmapProcessor beatmapProcessor)
|
||||
{
|
||||
var catchProcessor = (CatchBeatmapProcessor)beatmapProcessor;
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
public class CatchModHidden : ModHidden, IApplicableToDrawableRuleset<CatchHitObject>
|
||||
{
|
||||
public override LocalisableString Description => @"Play with fading fruits.";
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||
|
||||
private const double fade_out_offset_multiplier = 0.6;
|
||||
private const double fade_out_duration_multiplier = 0.44;
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
public override string Acronym => "MF";
|
||||
public override LocalisableString Description => "Dashing by default, slow down!";
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override IconUsage? Icon => OsuIcon.ModMovingFast;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax) };
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@@ -212,7 +213,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
[TestCaseSource(nameof(key_mod_multiplier_test_cases))]
|
||||
public void TestKeyModMultiplierCompatibility(DateTimeOffset endDate, string clientVersion, double expectedMultiplier)
|
||||
{
|
||||
var calculator = Ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(new ScoreInfo
|
||||
var calculator = Ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty(), new ScoreInfo
|
||||
{
|
||||
Date = endDate,
|
||||
ClientVersion = clientVersion
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
Mod = doubleTime,
|
||||
PassCondition = () => Player.ScoreProcessor.JudgedHits > 0
|
||||
&& Player.ScoreProcessor.Accuracy.Value == 1
|
||||
&& Player.ScoreProcessor.TotalScore.Value == (long)(1_000_000 * new ManiaScoreMultiplierCalculator(new ScoreMultiplierContext()).CalculateFor([doubleTime])),
|
||||
&& Player.ScoreProcessor.TotalScore.Value == (long)(1_000_000 * new ManiaScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty())).CalculateFor([doubleTime])),
|
||||
Autoplay = false,
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override string Acronym => Name;
|
||||
public abstract int KeyCount { get; }
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
public override bool Ranked => UsesDefaultConfiguration;
|
||||
|
||||
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
|
||||
|
||||
@@ -18,8 +18,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
public override string Acronym => "CS";
|
||||
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
|
||||
public override LocalisableString Description => "No more tricky speed changes!";
|
||||
|
||||
public override IconUsage? Icon => OsuIcon.ModConstantSpeed;
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
public override LocalisableString Description => @"Decrease the playfield's viewing area.";
|
||||
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
protected override CoverExpandDirection ExpandDirection => Direction.Value;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
|
||||
|
||||
@@ -7,9 +7,5 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModDoubleTime : ModDoubleTime, IManiaRateAdjustmentMod
|
||||
{
|
||||
// For now, all rate-increasing mods should be given a 1x multiplier in mania because it doesn't always
|
||||
// make the map harder and is more of a personal preference.
|
||||
// In the future, we can consider adjusting this by experimenting with not applying the hitwindow leniency.
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override LocalisableString Description => @"Double the stages, double the fun!";
|
||||
public override IconUsage? Icon => OsuIcon.ModDualStages;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
private bool isForCurrentRuleset;
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override string Acronym => "FI";
|
||||
public override IconUsage? Icon => OsuIcon.ModFadeIn;
|
||||
public override LocalisableString Description => @"Keys appear out of nowhere!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool ValidForFreestyleAsRequiredMod => false;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public partial class ManiaModFlashlight : ModFlashlight<ManiaHitObject>
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
||||
|
||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModHardRock : ModHardRock, IApplicableToHitObject
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => false;
|
||||
|
||||
public const double HIT_WINDOW_DIFFICULTY_MULTIPLIER = 1.4;
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
private const float coverage_increase_per_combo = 0.5f;
|
||||
|
||||
public override LocalisableString Description => @"Keys fade out before you hit them!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
|
||||
{
|
||||
|
||||
@@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
public override string Acronym => "HO";
|
||||
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
|
||||
public override LocalisableString Description => @"Replaces all hold notes with normal notes.";
|
||||
|
||||
public override IconUsage? Icon => OsuIcon.ModHoldOff;
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override string Name => "Invert";
|
||||
|
||||
public override string Acronym => "IN";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override LocalisableString Description => "Hold the keys. To the beat.";
|
||||
|
||||
|
||||
@@ -8,9 +8,5 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModNightcore : ModNightcore<ManiaHitObject>, IManiaRateAdjustmentMod
|
||||
{
|
||||
// For now, all rate-increasing mods should be given a 1x multiplier in mania because it doesn't always
|
||||
// make the map any harder and is more of a personal preference.
|
||||
// In the future, we can consider adjusting this by experimenting with not applying the hitwindow leniency.
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
public override LocalisableString Description => "No more timing the end of hold notes.";
|
||||
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
|
||||
public override IconUsage? Icon => OsuIcon.ModNoRelease;
|
||||
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public abstract partial class InputBlockingMod : Mod, IApplicableToDrawableRuleset<OsuHitObject>, IUpdatableByPlayfield
|
||||
{
|
||||
public override double ScoreMultiplier => 1.0;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(OsuModCinema) };
|
||||
public override ModType Type => ModType.Conversion;
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string Name => "Approach Different";
|
||||
public override string Acronym => "AD";
|
||||
public override LocalisableString Description => "Never trust the approach circles...";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override IconUsage? Icon => OsuIcon.ModApproachDifferent;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(IHidesApproachCircles), typeof(OsuModFreezeFrame) };
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModAutopilot;
|
||||
public override ModType Type => ModType.Automation;
|
||||
public override LocalisableString Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||
public override double ScoreMultiplier => 0.1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[]
|
||||
{
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModBlinds;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight) };
|
||||
public override bool Ranked => true;
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModBloom;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "The cursor blooms into.. a larger cursor!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
protected const float MIN_SIZE = 1;
|
||||
protected const float TRANSITION_DURATION = 100;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight), typeof(OsuModNoScope), typeof(ModTouchDevice) };
|
||||
|
||||
@@ -34,8 +34,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
public override LocalisableString Description => "Don't let their popping distract you!";
|
||||
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override IconUsage? Icon => OsuIcon.ModBubbles;
|
||||
|
||||
public override ModType Type => ModType.Fun;
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModDepth;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "3D. Almost.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModMagnetised), typeof(OsuModRepel), typeof(OsuModFreezeFrame), typeof(ModWithVisibilityAdjustment) }).ToArray();
|
||||
|
||||
private static readonly Vector3 camera_position = new Vector3(OsuPlayfield.BASE_SIZE.X * 0.5f, OsuPlayfield.BASE_SIZE.Y * 0.5f, -200);
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public partial class OsuModFlashlight : ModFlashlight<OsuHitObject>, IApplicableToDrawableHitObject
|
||||
{
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModBloom), typeof(OsuModBlinds) }).ToArray();
|
||||
|
||||
private const double default_follow_delay = 120;
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
public override IconUsage? Icon => OsuIcon.ModFreezeFrame;
|
||||
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override LocalisableString Description => "Burn the notes into your memory.";
|
||||
|
||||
/// <remarks>
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModHardRock : ModHardRock, IApplicableToHitObject
|
||||
{
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModMirror)).ToArray();
|
||||
|
||||
public void ApplyToHitObject(HitObject hitObject)
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public Bindable<bool> OnlyFadeApproachCircles { get; } = new BindableBool();
|
||||
|
||||
public override LocalisableString Description => @"Play with no approach circles and fading circles/sliders.";
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn), typeof(OsuModDepth), typeof(OsuModFreezeFrame) };
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModMagnetised;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "No need to chase the circles – your cursor is a magnet!";
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel), typeof(OsuModBubbles), typeof(OsuModDepth) };
|
||||
|
||||
[SettingSource("Attraction strength", "How strong the pull is.", 0)]
|
||||
|
||||
@@ -19,8 +19,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public override ModType Type => ModType.Fun;
|
||||
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
[SettingSource("Starting Size", "The initial size multiplier applied to all objects.")]
|
||||
public abstract BindableNumber<float> StartScale { get; }
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModRepel;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "Hit objects run away!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModBubbles), typeof(OsuModDepth) };
|
||||
|
||||
[SettingSource("Repulsion strength", "How strong the repulsion is.", 0)]
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModSpinIn;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "Circles spin in. No approach circles.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
// todo: this mod needs to be incompatible with "hidden" due to forcing the circle to remain opaque,
|
||||
// further implementation will be required for supporting that.
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModSpunOut;
|
||||
public override ModType Type => ModType.Automation;
|
||||
public override LocalisableString Description => @"Spinners will be automatically completed.";
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot), typeof(OsuModTargetPractice) };
|
||||
public override bool Ranked => UsesDefaultConfiguration;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModStrictTracking;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override LocalisableString Description => @"Once you start a slider, follow precisely or get a miss.";
|
||||
public override double ScoreMultiplier => 1.0;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModClassic), typeof(OsuModTargetPractice) };
|
||||
|
||||
public void ApplyToDrawableHitObject(DrawableHitObject drawable)
|
||||
|
||||
@@ -39,7 +39,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override IconUsage? Icon => OsuIcon.ModTargetPractice;
|
||||
public override LocalisableString Description => @"Practice keeping up with the beat of the song.";
|
||||
public override double ScoreMultiplier => 0.1;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
|
||||
{
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModTraceable;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override LocalisableString Description => "Put your faith in the approach circles...";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(IHidesApproachCircles), typeof(OsuModDepth) };
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModTransform;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "Everything rotates. EVERYTHING.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModWiggle), typeof(OsuModMagnetised), typeof(OsuModRepel), typeof(OsuModFreezeFrame), typeof(OsuModDepth) }).ToArray();
|
||||
|
||||
private float theta;
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModWiggle;
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "They just won't stay still...";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform), typeof(OsuModMagnetised), typeof(OsuModRepel), typeof(OsuModDepth) };
|
||||
|
||||
private const int wiggle_duration = 100; // (ms) Higher = fewer wiggles
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public override string Name => "Constant Speed";
|
||||
public override string Acronym => "CS";
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
public override LocalisableString Description => "No more tricky speed changes!";
|
||||
public override IconUsage? Icon => OsuIcon.ModConstantSpeed;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
|
||||
@@ -14,8 +14,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public partial class TaikoModFlashlight : ModFlashlight<TaikoHitObject>
|
||||
{
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||
|
||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
|
||||
{
|
||||
MinValue = 0.5f,
|
||||
|
||||
@@ -9,8 +9,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public class TaikoModHardRock : ModHardRock
|
||||
{
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplier factor added to the scrolling speed.
|
||||
/// </summary>
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
public class TaikoModHidden : ModHidden, IApplicableToDrawableRuleset<TaikoHitObject>
|
||||
{
|
||||
public override LocalisableString Description => @"Beats fade out before you hit them!";
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||
|
||||
/// <summary>
|
||||
/// How far away from the hit target should hitobjects start to fade out.
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public override string Name => "Simplified Rhythm";
|
||||
public override string Acronym => "SR";
|
||||
public override double ScoreMultiplier => 0.6;
|
||||
public override LocalisableString Description => "Simplify tricky rhythms!";
|
||||
public override IconUsage? Icon => OsuIcon.ModSimplifiedRhythm;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
public override LocalisableString Description => @"One key for dons, one key for kats.";
|
||||
|
||||
public override bool Ranked => true;
|
||||
public override double ScoreMultiplier => 1.0;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(TaikoModCinema) };
|
||||
public override ModType Type => ModType.Conversion;
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
public override LocalisableString Description => @"Dons become kats, kats become dons";
|
||||
public override IconUsage? Icon => OsuIcon.ModSwap;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModRandom)).ToArray();
|
||||
public override bool Ranked => true;
|
||||
|
||||
|
||||
@@ -91,7 +91,6 @@ namespace osu.Game.Tests.Mods
|
||||
{
|
||||
public override string Name => "Non-matching setting type mod";
|
||||
public override LocalisableString Description => "Description";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
|
||||
[SettingSource("Test setting")]
|
||||
|
||||
@@ -421,7 +421,6 @@ namespace osu.Game.Tests.Mods
|
||||
public override string Name => string.Empty;
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override string Acronym => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool HasImplementation => true;
|
||||
public override bool ValidForMultiplayer => false;
|
||||
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||
@@ -432,7 +431,6 @@ namespace osu.Game.Tests.Mods
|
||||
public override string Name => string.Empty;
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override string Acronym => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool HasImplementation => true;
|
||||
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||
}
|
||||
@@ -441,7 +439,6 @@ namespace osu.Game.Tests.Mods
|
||||
{
|
||||
public override string Name => string.Empty;
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override string Acronym => string.Empty;
|
||||
public override bool HasImplementation => true;
|
||||
public override bool ValidForFreestyleAsRequiredMod => false;
|
||||
|
||||
@@ -59,8 +59,6 @@ namespace osu.Game.Tests.Mods
|
||||
|
||||
public abstract class TestModCustomisable : Mod, IApplicableMod
|
||||
{
|
||||
public override double ScoreMultiplier => 1.0;
|
||||
|
||||
public override LocalisableString Description => "This is a customisable test mod.";
|
||||
|
||||
public override ModType Type => ModType.Conversion;
|
||||
|
||||
@@ -161,7 +161,6 @@ namespace osu.Game.Tests.NonVisual
|
||||
public override string Name => nameof(ModA);
|
||||
public override string Acronym => nameof(ModA);
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithA), typeof(ModIncompatibleWithAAndB) };
|
||||
}
|
||||
@@ -171,7 +170,6 @@ namespace osu.Game.Tests.NonVisual
|
||||
public override string Name => nameof(ModB);
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override string Acronym => nameof(ModB);
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithAAndB) };
|
||||
}
|
||||
@@ -181,7 +179,6 @@ namespace osu.Game.Tests.NonVisual
|
||||
public override string Name => nameof(ModC);
|
||||
public override string Acronym => nameof(ModC);
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
|
||||
private class ModIncompatibleWithA : Mod
|
||||
@@ -189,7 +186,6 @@ namespace osu.Game.Tests.NonVisual
|
||||
public override string Name => $"Incompatible With {nameof(ModA)}";
|
||||
public override string Acronym => $"Incompatible With {nameof(ModA)}";
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModA) };
|
||||
}
|
||||
@@ -208,7 +204,6 @@ namespace osu.Game.Tests.NonVisual
|
||||
public override string Name => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
|
||||
public override string Acronym => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModA), typeof(ModB) };
|
||||
}
|
||||
|
||||
@@ -185,7 +185,6 @@ namespace osu.Game.Tests.Online
|
||||
public override string Name => "Test Mod";
|
||||
public override string Acronym => "TM";
|
||||
public override LocalisableString Description => "This is a test mod.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
[SettingSource("Test")]
|
||||
public BindableNumber<double> TestSetting { get; } = new BindableDouble
|
||||
@@ -202,7 +201,6 @@ namespace osu.Game.Tests.Online
|
||||
public override string Name => "Test Mod";
|
||||
public override string Acronym => "TMTR";
|
||||
public override LocalisableString Description => "This is a test mod.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
[SettingSource("Initial rate", "The starting speed of the track")]
|
||||
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1.5)
|
||||
|
||||
@@ -104,7 +104,6 @@ namespace osu.Game.Tests.Online
|
||||
public override string Name => "Test Mod";
|
||||
public override string Acronym => "TM";
|
||||
public override LocalisableString Description => "This is a test mod.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
[SettingSource("Test")]
|
||||
public BindableNumber<double> TestSetting { get; } = new BindableDouble
|
||||
@@ -121,7 +120,6 @@ namespace osu.Game.Tests.Online
|
||||
public override string Name => "Test Mod";
|
||||
public override string Acronym => "TMTR";
|
||||
public override LocalisableString Description => "This is a test mod.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
[SettingSource("Initial rate", "The starting speed of the track")]
|
||||
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1.5)
|
||||
@@ -148,7 +146,6 @@ namespace osu.Game.Tests.Online
|
||||
public override string Name => "Test Mod";
|
||||
public override string Acronym => "TM";
|
||||
public override LocalisableString Description => "This is a test mod.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
[SettingSource("Test")]
|
||||
public Bindable<TestEnum> TestSetting { get; } = new Bindable<TestEnum>();
|
||||
|
||||
@@ -222,12 +222,10 @@ namespace osu.Game.Tests.Resources
|
||||
|
||||
private class TestModHardRock : ModHardRock
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
|
||||
private class TestModDoubleTime : ModDoubleTime
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
@@ -13,7 +14,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
[Test]
|
||||
public void TestFlatMultiplier()
|
||||
{
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
|
||||
double multiplier = calculator.CalculateFor([new OsuModEasy()]);
|
||||
|
||||
@@ -23,7 +24,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
[Test]
|
||||
public void TestSettingDependentMultiplier()
|
||||
{
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
|
||||
double multiplier = calculator.CalculateFor([new OsuModDaycore { SpeedChange = { Value = 0.6 } }]);
|
||||
|
||||
@@ -31,7 +32,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContextDependentMultiplier()
|
||||
public void TestScoreDependentMultiplier()
|
||||
{
|
||||
TestScoreMultiplierCalculator calculator;
|
||||
|
||||
@@ -39,20 +40,39 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
multiplier = calculator.CalculateFor([new OsuModHardRock()]);
|
||||
Assert.That(multiplier, Is.EqualTo(1.4));
|
||||
|
||||
calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new ScoreInfo { ClientVersion = "2024.123.0" }));
|
||||
calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty(), new ScoreInfo { ClientVersion = "2024.123.0" }));
|
||||
multiplier = calculator.CalculateFor([new OsuModHardRock()]);
|
||||
Assert.That(multiplier, Is.EqualTo(1.2));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDifficultyDependentMultiplier()
|
||||
{
|
||||
TestScoreMultiplierCalculator calculator;
|
||||
|
||||
double multiplier;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
multiplier = calculator.CalculateFor([new OsuModEasy()]);
|
||||
Assert.That(multiplier, Is.EqualTo(0.15));
|
||||
|
||||
calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty { ApproachRate = 0 }));
|
||||
multiplier = calculator.CalculateFor([new OsuModEasy()]);
|
||||
Assert.That(multiplier, Is.EqualTo(0.1));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCombinationMultiplier()
|
||||
{
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
|
||||
double multiplier = calculator.CalculateFor([new OsuModEasy(), new OsuModDaycore()]);
|
||||
|
||||
@@ -62,7 +82,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
[Test]
|
||||
public void TestCombinationAndFlatMultipliers()
|
||||
{
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var calculator = new TestScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
|
||||
double multiplier = calculator.CalculateFor([new OsuModDaycore(), new OsuModHardRock(), new OsuModEasy()]);
|
||||
|
||||
@@ -74,7 +94,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
public TestScoreMultiplierCalculator(ScoreMultiplierContext context)
|
||||
: base(context)
|
||||
{
|
||||
Single<OsuModEasy>(hasMultiplier: 0.15);
|
||||
Single<OsuModEasy>(hasMultiplier: context.BeatmapDifficultyWithoutMods.ApproachRate == 0 ? 0.1 : 0.15);
|
||||
Single<OsuModDaycore>(hasMultiplier: daycore => (1 + daycore.SpeedChange.Value) / 4);
|
||||
Single<OsuModHardRock>(hasMultiplier: _ => context.Score?.ClientVersion == "2024.123.0" ? 1.2 : 1.4);
|
||||
Combination<OsuModEasy, OsuModDaycore>(hasMultiplier: (_, _) => 0.003);
|
||||
|
||||
@@ -481,6 +481,29 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
Assert.That(scoreProcessor.HighestCombo.Value, Is.Zero);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScoreMultiplier()
|
||||
{
|
||||
Mod[] mods = new Mod[] { new OsuModHardRock() };
|
||||
|
||||
scoreProcessor = new TestScoreProcessor();
|
||||
scoreProcessor.Mods.Value = mods;
|
||||
|
||||
var workingBeatmap = new TestWorkingBeatmap(beatmap);
|
||||
var playableBeatmap = workingBeatmap.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, mods);
|
||||
|
||||
scoreProcessor.ApplyBeatmap(playableBeatmap);
|
||||
|
||||
var judgementResult = new JudgementResult(beatmap.HitObjects.Single(), new OsuJudgement())
|
||||
{
|
||||
Type = HitResult.Great,
|
||||
};
|
||||
scoreProcessor.ApplyResult(judgementResult);
|
||||
|
||||
Assert.That(scoreProcessor.MaximumTotalScore, Is.EqualTo(1_000_000 * 1.1).Within(0.5d));
|
||||
Assert.That(scoreProcessor.GetDisplayScore(ScoringMode.Standardised), Is.EqualTo(1_000_000 * 1.1).Within(0.5d));
|
||||
}
|
||||
|
||||
private class TestJudgement : Judgement
|
||||
{
|
||||
public override HitResult MaxResult { get; }
|
||||
@@ -537,9 +560,20 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||
|
||||
public override ScoreMultiplierCalculator CreateScoreMultiplierCalculator(ScoreMultiplierContext context) => new TestScoreMultiplierCalculator(context);
|
||||
|
||||
public override string Description => string.Empty;
|
||||
public override string ShortName => string.Empty;
|
||||
}
|
||||
|
||||
private class TestScoreMultiplierCalculator : ScoreMultiplierCalculator
|
||||
{
|
||||
public TestScoreMultiplierCalculator(ScoreMultiplierContext context)
|
||||
: base(context)
|
||||
{
|
||||
Single<OsuModHardRock>(hasMultiplier: context.BeatmapDifficultyWithoutMods.CircleSize == 4 ? 1.1 : 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
@@ -120,7 +121,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
private void assertModsMultiplier(Ruleset ruleset, IEnumerable<Mod> mods)
|
||||
{
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
double multiplier = scoreMultiplierCalculator.CalculateFor(mods);
|
||||
string expectedValue = ModUtils.FormatScoreMultiplier(multiplier).ToString();
|
||||
|
||||
|
||||
@@ -244,7 +244,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
public override string Name => string.Empty;
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override double ScoreMultiplier => 1.0;
|
||||
public override string Acronym => "Test";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ using osu.Framework.Localisation;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
@@ -124,7 +125,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddUntilStep("two panels active", () => modSelectOverlay.ChildrenOfType<ModPanel>().Count(panel => panel.Active.Value) == 2);
|
||||
AddAssert("mod multiplier correct", () =>
|
||||
{
|
||||
double multiplier = new OsuScoreMultiplierCalculator(new ScoreMultiplierContext()).CalculateFor(SelectedMods.Value);
|
||||
double multiplier = new OsuScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty())).CalculateFor(SelectedMods.Value);
|
||||
return Precision.AlmostEquals(multiplier, this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
|
||||
});
|
||||
assertCustomisationToggleState(disabled: false, active: false);
|
||||
@@ -139,7 +140,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddUntilStep("two panels active", () => modSelectOverlay.ChildrenOfType<ModPanel>().Count(panel => panel.Active.Value) == 2);
|
||||
AddAssert("mod multiplier correct", () =>
|
||||
{
|
||||
double multiplier = new OsuScoreMultiplierCalculator(new ScoreMultiplierContext()).CalculateFor(SelectedMods.Value);
|
||||
double multiplier = new OsuScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty())).CalculateFor(SelectedMods.Value);
|
||||
return Precision.AlmostEquals(multiplier, this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
|
||||
});
|
||||
assertCustomisationToggleState(disabled: false, active: false);
|
||||
@@ -1146,7 +1147,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
public override string Name => "Unimplemented mod";
|
||||
public override string Acronym => "UM";
|
||||
public override LocalisableString Description => "A mod that is not implemented.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,10 @@ namespace osu.Game.Database
|
||||
}
|
||||
|
||||
var ruleset = score.Ruleset.CreateInstance();
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(score));
|
||||
|
||||
Debug.Assert(score.BeatmapInfo != null);
|
||||
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(score.BeatmapInfo.Difficulty, score));
|
||||
double modMultiplier = scoreMultiplierCalculator.CalculateFor(score.Mods);
|
||||
|
||||
return (long)Math.Round((1000000 * (accuracyPortion * accuracyScore + (1 - accuracyPortion) * comboScore) + bonusScore) * modMultiplier);
|
||||
@@ -351,7 +354,7 @@ namespace osu.Game.Database
|
||||
long maximumLegacyBaseScore = maximumLegacyAccuracyScore + maximumLegacyComboScore;
|
||||
double bonusProportion = Math.Max(0, ((long)score.LegacyTotalScore - maximumLegacyBaseScore) * maximumLegacyBonusRatio);
|
||||
|
||||
var modMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var modMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(difficulty));
|
||||
double modMultiplier = modMultiplierCalculator.CalculateFor(score.Mods);
|
||||
|
||||
long convertedTotalScoreWithoutMods;
|
||||
|
||||
@@ -102,6 +102,8 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
if (beatmapAttributesDisplay != null)
|
||||
beatmapAttributesDisplay.BeatmapInfo.Value = b.NewValue?.BeatmapInfo;
|
||||
|
||||
updateInformation();
|
||||
}, true);
|
||||
|
||||
Ruleset.BindValueChanged(_ => updateInformation());
|
||||
@@ -122,9 +124,11 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
private void updateInformation()
|
||||
{
|
||||
if (rankingInformationDisplay != null)
|
||||
WorkingBeatmap? workingBeatmap = Beatmap.Value;
|
||||
|
||||
if (rankingInformationDisplay != null && workingBeatmap != null)
|
||||
{
|
||||
var scoreMultiplierCalculator = Ruleset.Value?.CreateInstance().CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var scoreMultiplierCalculator = Ruleset.Value?.CreateInstance().CreateScoreMultiplierCalculator(new ScoreMultiplierContext(workingBeatmap.BeatmapInfo.Difficulty));
|
||||
double multiplier = scoreMultiplierCalculator?.CalculateFor(ActiveMods.Value) ?? 1;
|
||||
|
||||
rankingInformationDisplay.ModMultiplier.Value = multiplier;
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace osu.Game.Rulesets.Mods
|
||||
/// The score multiplier of this mod.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public abstract double ScoreMultiplier { get; }
|
||||
[Obsolete("This property is no longer used to calculate the score multiplier. Use `Ruleset.CreateScoreMultiplierCalculator()` instead.")]
|
||||
public virtual double ScoreMultiplier => 1;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this mod is implemented (and playable).
|
||||
|
||||
@@ -30,8 +30,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
|
||||
public override double ScoreMultiplier => 1.0;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModEasyWithExtraLives), typeof(ModPerfect) }).ToArray();
|
||||
|
||||
public override bool RequiresConfiguration => false;
|
||||
|
||||
@@ -33,8 +33,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override ModType Type => ModType.Fun;
|
||||
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
|
||||
public sealed override bool ValidForMultiplayer => false;
|
||||
public sealed override bool ValidForMultiplayerAsFreeMod => false;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModAutoplay;
|
||||
public override ModType Type => ModType.Automation;
|
||||
public override LocalisableString Description => "Watch a perfect automated play through the song.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public sealed override bool UserPlayable => false;
|
||||
public sealed override bool ValidForMultiplayer => false;
|
||||
|
||||
@@ -40,7 +40,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "BR";
|
||||
public override IconUsage? Icon => OsuIcon.ModBarrelRoll;
|
||||
public override LocalisableString Description => "The whole playfield is on a wheel!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override IEnumerable<(LocalisableString setting, LocalisableString value)> SettingDescription
|
||||
{
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override string Acronym => "CL";
|
||||
|
||||
public override double ScoreMultiplier => 0.96;
|
||||
|
||||
public override IconUsage? Icon => OsuIcon.ModClassic;
|
||||
|
||||
public override LocalisableString Description => "Feeling nostalgic?";
|
||||
|
||||
@@ -30,13 +30,10 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
private readonly BindableNumber<double> tempoAdjust = new BindableDouble(1);
|
||||
private readonly BindableNumber<double> freqAdjust = new BindableDouble(1);
|
||||
private readonly RateAdjustModHelper rateAdjustHelper;
|
||||
|
||||
protected ModDaycore()
|
||||
{
|
||||
rateAdjustHelper = new RateAdjustModHelper(SpeedChange);
|
||||
|
||||
// intentionally not deferring the speed change handling to `RateAdjustModHelper`
|
||||
// intentionally not using `RateAdjustModHelper`
|
||||
// as the expected result of operation is not the same (daycore should preserve constant pitch).
|
||||
SpeedChange.BindValueChanged(val =>
|
||||
{
|
||||
@@ -50,7 +47,5 @@ namespace osu.Game.Rulesets.Mods
|
||||
track.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
|
||||
track.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
|
||||
}
|
||||
|
||||
public override double ScoreMultiplier => rateAdjustHelper.ScoreMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override IconUsage? Icon => OsuIcon.ModDifficultyAdjust;
|
||||
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
|
||||
public override bool RequiresConfiguration => true;
|
||||
|
||||
public override bool ValidForFreestyleAsRequiredMod => true;
|
||||
|
||||
@@ -56,7 +56,5 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
rateAdjustHelper.ApplyToTrack(track);
|
||||
}
|
||||
|
||||
public override double ScoreMultiplier => rateAdjustHelper.ScoreMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "EZ";
|
||||
public override IconUsage? Icon => OsuIcon.ModEasy;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock), typeof(ModDifficultyAdjust) };
|
||||
public override bool Ranked => UsesDefaultConfiguration;
|
||||
public override bool ValidForFreestyleAsRequiredMod => true;
|
||||
|
||||
@@ -56,7 +56,5 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
rateAdjustHelper.ApplyToTrack(track);
|
||||
}
|
||||
|
||||
public override double ScoreMultiplier => rateAdjustHelper.ScoreMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,5 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "MR";
|
||||
public override IconUsage? Icon => OsuIcon.ModMirror;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModMuted;
|
||||
public override LocalisableString Description => "Can you still feel the rhythm without music?";
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
public override bool ValidForFreestyleAsRequiredMod => true;
|
||||
}
|
||||
|
||||
@@ -41,13 +41,9 @@ namespace osu.Game.Rulesets.Mods
|
||||
private readonly BindableNumber<double> tempoAdjust = new BindableDouble(1);
|
||||
private readonly BindableNumber<double> freqAdjust = new BindableDouble(1);
|
||||
|
||||
private readonly RateAdjustModHelper rateAdjustHelper;
|
||||
|
||||
protected ModNightcore()
|
||||
{
|
||||
rateAdjustHelper = new RateAdjustModHelper(SpeedChange);
|
||||
|
||||
// intentionally not deferring the speed change handling to `RateAdjustModHelper`
|
||||
// intentionally not using `RateAdjustModHelper`
|
||||
// as the expected result of operation is not the same (nightcore should preserve constant pitch).
|
||||
SpeedChange.BindValueChanged(val =>
|
||||
{
|
||||
@@ -61,8 +57,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
track.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
|
||||
track.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
|
||||
}
|
||||
|
||||
public override double ScoreMultiplier => rateAdjustHelper.ScoreMultiplier;
|
||||
}
|
||||
|
||||
public abstract partial class ModNightcore<TObject> : ModNightcore, IApplicableToDrawableRuleset<TObject>
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModNoFail;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override LocalisableString Description => "You can't fail, no matter what.";
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModFailCondition), typeof(ModCinema) };
|
||||
public override bool Ranked => UsesDefaultConfiguration;
|
||||
public override bool ValidForFreestyleAsRequiredMod => true;
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Name => "No Mod";
|
||||
public override string Acronym => "NM";
|
||||
public override LocalisableString Description => "No mods applied.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override IconUsage? Icon => OsuIcon.ModNoMod;
|
||||
public override ModType Type => ModType.System;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "NS";
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override IconUsage? Icon => OsuIcon.ModNoScope;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "PF";
|
||||
public override IconUsage? Icon => OsuIcon.ModPerfect;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override LocalisableString Description => "SS or quit.";
|
||||
public override bool Ranked => true;
|
||||
public override bool ValidForFreestyleAsRequiredMod => true;
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "RD";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override IconUsage? Icon => OsuIcon.ModRandom;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
|
||||
public Bindable<int?> Seed { get; } = new Bindable<int?>();
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "RX";
|
||||
public override IconUsage? Icon => OsuIcon.ModRelax;
|
||||
public override ModType Type => ModType.Automation;
|
||||
public override double ScoreMultiplier => 0.1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModScoreV2;
|
||||
public override ModType Type => ModType.System;
|
||||
public override LocalisableString Description => "Score set on earlier osu! versions with the V2 scoring algorithm active.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool UserPlayable => false;
|
||||
public override bool ValidForMultiplayer => false;
|
||||
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModSuddenDeath;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override LocalisableString Description => "Miss and fail.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
public override bool ValidForFreestyleAsRequiredMod => true;
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Name => "Synesthesia";
|
||||
public override string Acronym => "SY";
|
||||
public override LocalisableString Description => "Colours hit objects based on the rhythm.";
|
||||
public override double ScoreMultiplier => 0.8;
|
||||
public override IconUsage? Icon => OsuIcon.ModSynesthesia;
|
||||
public override ModType Type => ModType.Fun;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
/// </summary>
|
||||
public const double FINAL_RATE_PROGRESS = 0.75f;
|
||||
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
|
||||
[SettingSource("Initial rate", "The starting speed of the track", SettingControlType = typeof(MultiplierSettingsSlider))]
|
||||
public abstract BindableNumber<double> InitialRate { get; }
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public sealed override string Acronym => "TD";
|
||||
public sealed override IconUsage? Icon => OsuIcon.ModTouchDevice;
|
||||
public sealed override LocalisableString Description => "Automatically applied to plays on devices with a touchscreen.";
|
||||
public sealed override double ScoreMultiplier => 1;
|
||||
public sealed override ModType Type => ModType.System;
|
||||
public sealed override bool ValidForMultiplayer => false;
|
||||
public sealed override bool ValidForMultiplayerAsFreeMod => false;
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Name => string.Empty;
|
||||
public override string Acronym => string.Empty;
|
||||
public override LocalisableString Description => string.Empty;
|
||||
public override double ScoreMultiplier => 0;
|
||||
|
||||
public Mod[] Mods { get; }
|
||||
|
||||
|
||||
@@ -18,26 +18,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
private BindableBool? adjustPitch;
|
||||
|
||||
/// <summary>
|
||||
/// The score multiplier for the current <see cref="SpeedChange"/>.
|
||||
/// </summary>
|
||||
public double ScoreMultiplier
|
||||
{
|
||||
get
|
||||
{
|
||||
// Round to the nearest multiple of 0.1.
|
||||
double value = (int)(SpeedChange.Value * 10) / 10.0;
|
||||
|
||||
// Offset back to 0.
|
||||
value -= 1;
|
||||
|
||||
if (SpeedChange.Value >= 1)
|
||||
return 1 + value / 5;
|
||||
else
|
||||
return 0.6 + value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new <see cref="RateAdjustModHelper"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Name => $"Unknown mod ({OriginalAcronym})";
|
||||
public override string Acronym => $"{OriginalAcronym}??";
|
||||
public override LocalisableString Description => "This mod could not be resolved by the game.";
|
||||
public override double ScoreMultiplier => 0;
|
||||
|
||||
public override bool UserPlayable => false;
|
||||
public override bool ValidForMultiplayer => false;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
@@ -95,6 +96,12 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// </summary>
|
||||
public class ScoreMultiplierContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The difficulty info for the beatmap that the multipliers are calculated for.
|
||||
/// This must be the difficulty info for the beatmap BEFORE any mod application.
|
||||
/// </summary>
|
||||
public IBeatmapDifficultyInfo BeatmapDifficultyWithoutMods { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The score that the multipliers are calculated for.
|
||||
/// Mostly relevant and present in backwards compatibility scenarios.
|
||||
@@ -104,24 +111,19 @@ namespace osu.Game.Rulesets.Scoring
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance.
|
||||
/// Use this in situations wherein the current valid score multipliers are needed.
|
||||
/// </summary>
|
||||
public ScoreMultiplierContext()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance.
|
||||
/// Use this in backwards compatibility scenarios when dealing with a specific <paramref name="score"/>.
|
||||
/// </summary>
|
||||
/// <param name="beatmapDifficultyWithoutMods">
|
||||
/// The difficulty info for the beatmap that the multipliers are calculated for.
|
||||
/// This must be the difficulty info for the beatmap BEFORE any mod application.
|
||||
/// </param>
|
||||
/// <param name="score">
|
||||
/// The score that the multipliers are calculated for.
|
||||
/// Mostly relevant and present in backwards compatibility scenarios.
|
||||
/// In usages where the current valid score multipliers are required, pass <see langword="null"/> or use a constructor that does not require this.
|
||||
/// In usages where the current valid score multipliers are required, pass <see langword="null"/> or omit this parameter entirely.
|
||||
/// </param>
|
||||
public ScoreMultiplierContext(ScoreInfo? score)
|
||||
public ScoreMultiplierContext(IBeatmapDifficultyInfo beatmapDifficultyWithoutMods, ScoreInfo? score = null)
|
||||
{
|
||||
BeatmapDifficultyWithoutMods = beatmapDifficultyWithoutMods;
|
||||
Score = score;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,11 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// </summary>
|
||||
public readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||
|
||||
/// <summary>
|
||||
/// The current beatmap.
|
||||
/// </summary>
|
||||
public readonly Bindable<IBeatmap?> Beatmap = new Bindable<IBeatmap?>();
|
||||
|
||||
/// <summary>
|
||||
/// The current rank.
|
||||
/// </summary>
|
||||
@@ -206,16 +211,27 @@ namespace osu.Game.Rulesets.Scoring
|
||||
|
||||
Mods.ValueChanged += mods =>
|
||||
{
|
||||
var calculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
scoreMultiplier = calculator.CalculateFor(mods.NewValue);
|
||||
|
||||
updateScoreMultiplier();
|
||||
updateScore();
|
||||
updateRank();
|
||||
};
|
||||
|
||||
Beatmap.ValueChanged += beatmap =>
|
||||
{
|
||||
updateScoreMultiplier();
|
||||
};
|
||||
}
|
||||
|
||||
public override void ApplyBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
// NOTE: The ordering of operations here is significant.
|
||||
// `Beatmap.Value` must be set before `base.ApplyBeatmap()` because changes to `Beatmap.Value`
|
||||
// trigger recalculation of `scoreMultiplier`,
|
||||
// and `base.ApplyBeatmap()` calls `SimulateAutoplay()` then `Reset(storeResults: true)`.
|
||||
// failing to calculate the correct score multiplier *before* autoplay simulation would result in
|
||||
// storing the incorrect value of `MaximumTotalScore`.
|
||||
Beatmap.Value = beatmap;
|
||||
|
||||
base.ApplyBeatmap(beatmap);
|
||||
beatmapApplied = true;
|
||||
}
|
||||
@@ -399,6 +415,15 @@ namespace osu.Game.Rulesets.Scoring
|
||||
rank.Value = newRank;
|
||||
}
|
||||
|
||||
private void updateScoreMultiplier()
|
||||
{
|
||||
if (Beatmap.Value == null)
|
||||
return;
|
||||
|
||||
var calculator = Ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(Beatmap.Value.BeatmapInfo.Difficulty));
|
||||
scoreMultiplier = calculator.CalculateFor(Mods.Value);
|
||||
}
|
||||
|
||||
protected virtual double ComputeTotalScore(double comboProgress, double accuracyProgress, double bonusPortion)
|
||||
{
|
||||
return 500000 * Accuracy.Value * comboProgress +
|
||||
|
||||
@@ -258,8 +258,10 @@ namespace osu.Game.Scoring.Legacy
|
||||
|
||||
public static void PopulateTotalScoreWithoutMods(ScoreInfo score)
|
||||
{
|
||||
Debug.Assert(score.BeatmapInfo != null);
|
||||
|
||||
var ruleset = score.Ruleset.CreateInstance();
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(score));
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(score.BeatmapInfo.Difficulty, score));
|
||||
double modMultiplier = scoreMultiplierCalculator.CalculateFor(score.Mods);
|
||||
|
||||
score.TotalScoreWithoutMods = (long)Math.Round(score.TotalScore / modMultiplier);
|
||||
|
||||
@@ -60,8 +60,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
|
||||
client.MatchmakingQueueJoined += onMatchmakingQueueJoined;
|
||||
client.MatchmakingQueueLeft += onMatchmakingQueueLeft;
|
||||
client.MatchmakingRoomInvited += onMatchmakingRoomInvited;
|
||||
client.MatchmakingDuelIssued += onMatchmakingDuelIssued;
|
||||
client.MatchmakingRoomReady += onMatchmakingRoomReady;
|
||||
client.MatchmakingDuelIssued += onMatchmakingDuelIssued;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -133,9 +133,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
|
||||
return;
|
||||
|
||||
isBackgrounded = true;
|
||||
|
||||
if (CurrentState.Value == ScreenQueue.MatchmakingScreenState.Queueing)
|
||||
postNotification();
|
||||
postNotification();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -147,7 +145,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
|
||||
return;
|
||||
|
||||
isBackgrounded = false;
|
||||
closeNotifications();
|
||||
closeNotification();
|
||||
}
|
||||
|
||||
private void onRoomUpdated() => Scheduler.Add(() =>
|
||||
@@ -160,37 +158,34 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
|
||||
{
|
||||
CurrentState.Value = ScreenQueue.MatchmakingScreenState.Queueing;
|
||||
|
||||
if (isBackgrounded)
|
||||
{
|
||||
closeNotifications();
|
||||
postNotification();
|
||||
}
|
||||
postNotification();
|
||||
});
|
||||
|
||||
private void onMatchmakingQueueLeft() => Scheduler.Add(() =>
|
||||
{
|
||||
if (CurrentState.Value != ScreenQueue.MatchmakingScreenState.InRoom)
|
||||
CurrentState.Value = ScreenQueue.MatchmakingScreenState.Idle;
|
||||
CurrentState.Value = ScreenQueue.MatchmakingScreenState.Idle;
|
||||
|
||||
closeNotifications();
|
||||
closeNotification();
|
||||
});
|
||||
|
||||
private void onMatchmakingRoomInvited(MatchmakingRoomInvitationParams invitation) => Scheduler.Add(() =>
|
||||
{
|
||||
if (isBackgrounded)
|
||||
postNotification();
|
||||
|
||||
CurrentState.Value = ScreenQueue.MatchmakingScreenState.PendingAccept;
|
||||
|
||||
postNotification();
|
||||
backgroundNotification?.Complete(invitation);
|
||||
backgroundNotification = null;
|
||||
});
|
||||
|
||||
private void onMatchmakingRoomReady(long roomId, string password) => Scheduler.Add(() =>
|
||||
{
|
||||
CurrentState.Value = ScreenQueue.MatchmakingScreenState.InRoom;
|
||||
|
||||
client.JoinRoom(new Room { RoomID = roomId }, password).FireAndForget();
|
||||
});
|
||||
|
||||
private void onMatchmakingDuelIssued(MatchmakingDuelIssuedParams duel)
|
||||
{
|
||||
handleDuelRequestAsync().FireAndForget();
|
||||
|
||||
async Task handleDuelRequestAsync()
|
||||
Task.Run(async () =>
|
||||
{
|
||||
APIUser? user = await users.GetUserAsync(duel.UserId).ConfigureAwait(false);
|
||||
|
||||
@@ -198,34 +193,35 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
|
||||
return;
|
||||
|
||||
Scheduler.Add(() => notifications?.Post(new DuelNotification(this, user, duel)));
|
||||
}
|
||||
}).FireAndForget();
|
||||
}
|
||||
|
||||
private void onMatchmakingRoomReady(long roomId, string password) => Scheduler.Add(() =>
|
||||
{
|
||||
client.JoinRoom(new Room { RoomID = roomId }, password)
|
||||
.FireAndForget(() => Scheduler.Add(() =>
|
||||
{
|
||||
CurrentState.Value = ScreenQueue.MatchmakingScreenState.InRoom;
|
||||
}));
|
||||
});
|
||||
|
||||
private void postNotification()
|
||||
{
|
||||
if (backgroundNotification != null)
|
||||
// Check if we can re-use an existing notification.
|
||||
if (backgroundNotification?.State == ProgressNotificationState.Active || backgroundNotification?.State == ProgressNotificationState.Queued)
|
||||
return;
|
||||
|
||||
// Existing notification could be in a post-completion state.
|
||||
closeNotification();
|
||||
|
||||
if (!isBackgrounded)
|
||||
return;
|
||||
|
||||
if (CurrentState.Value != ScreenQueue.MatchmakingScreenState.Queueing)
|
||||
return;
|
||||
|
||||
notifications?.Post(backgroundNotification = new BackgroundQueueNotification(this));
|
||||
}
|
||||
|
||||
private void closeNotifications()
|
||||
private void closeNotification()
|
||||
{
|
||||
if (backgroundNotification != null)
|
||||
{
|
||||
backgroundNotification.State = ProgressNotificationState.Cancelled;
|
||||
backgroundNotification.CloseAll();
|
||||
backgroundNotification = null;
|
||||
}
|
||||
if (backgroundNotification == null)
|
||||
return;
|
||||
|
||||
backgroundNotification.State = ProgressNotificationState.Cancelled;
|
||||
backgroundNotification.CloseAll();
|
||||
backgroundNotification = null;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
@@ -239,6 +235,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
|
||||
client.MatchmakingQueueLeft -= onMatchmakingQueueLeft;
|
||||
client.MatchmakingRoomInvited -= onMatchmakingRoomInvited;
|
||||
client.MatchmakingRoomReady -= onMatchmakingRoomReady;
|
||||
client.MatchmakingDuelIssued -= onMatchmakingDuelIssued;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,12 +287,21 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
|
||||
|
||||
public void Complete(MatchmakingRoomInvitationParams invitation)
|
||||
{
|
||||
if (State != ProgressNotificationState.Active && State != ProgressNotificationState.Queued)
|
||||
return;
|
||||
|
||||
CompletionClickAction = () =>
|
||||
{
|
||||
client.MatchmakingAcceptInvitation().FireAndForget();
|
||||
controller.CurrentState.Value = ScreenQueue.MatchmakingScreenState.AcceptedWaitingForRoom;
|
||||
performer?.PerformFromScreen(s =>
|
||||
{
|
||||
client.MatchmakingAcceptInvitation().FireAndForget();
|
||||
controller.CurrentState.Value = ScreenQueue.MatchmakingScreenState.AcceptedWaitingForRoom;
|
||||
|
||||
performer?.PerformFromScreen(s => s.Push(new ScreenIntro(invitation.Type)));
|
||||
if (s is ScreenIntro || s is ScreenQueue)
|
||||
return;
|
||||
|
||||
s.Push(new ScreenIntro(invitation.Type));
|
||||
}, [typeof(ScreenIntro), typeof(ScreenQueue)]);
|
||||
|
||||
Close(false);
|
||||
return true;
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace osu.Game.Screens.Select
|
||||
new StatisticRow(s.DisplayName.ToUpper(), s.Count.ToLocalisableString("N0"), colours.ForHitResult(s.Result)));
|
||||
|
||||
var ruleset = value.Ruleset.CreateInstance();
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var scoreMultiplierCalculator = ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(score.BeatmapInfo!.Difficulty));
|
||||
double multiplier = scoreMultiplierCalculator.CalculateFor(value.Mods);
|
||||
|
||||
var generalStatistics = new[]
|
||||
|
||||
@@ -15,6 +15,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@@ -78,6 +79,9 @@ namespace osu.Game.Screens.Select
|
||||
[Resolved]
|
||||
private OsuGameBase game { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
|
||||
|
||||
private IBindable<Language> currentLanguage = null!;
|
||||
|
||||
public FooterButtonMods(ModSelectOverlay overlay)
|
||||
@@ -175,6 +179,7 @@ namespace osu.Game.Screens.Select
|
||||
currentLanguage.BindValueChanged(_ => ScheduleAfterChildren(updateDisplay));
|
||||
|
||||
Ruleset.BindValueChanged(_ => updateDisplay());
|
||||
beatmap.BindValueChanged(_ => updateDisplay());
|
||||
Mods.BindValueChanged(m =>
|
||||
{
|
||||
modSettingChangeTracker?.Dispose();
|
||||
@@ -244,7 +249,7 @@ namespace osu.Game.Screens.Select
|
||||
modDisplay.FadeIn(duration, easing);
|
||||
}
|
||||
|
||||
var scoreMultiplierCalculator = Ruleset.Value?.CreateInstance().CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
var scoreMultiplierCalculator = Ruleset.Value?.CreateInstance().CreateScoreMultiplierCalculator(new ScoreMultiplierContext(beatmap.Value.BeatmapInfo.Difficulty));
|
||||
double multiplier = scoreMultiplierCalculator?.CalculateFor(Mods.Value) ?? 1;
|
||||
multiplierText.Text = ModUtils.FormatScoreMultiplier(multiplier);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@@ -26,16 +27,8 @@ namespace osu.Game.Tests.Rulesets
|
||||
|
||||
protected void TestModCombination(IEnumerable<Mod> mods, double expectedMultiplier)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
double multiplierViaOldAPI = 1;
|
||||
foreach (var mod in mods)
|
||||
multiplierViaOldAPI *= mod.ScoreMultiplier;
|
||||
Assert.That(multiplierViaOldAPI, Is.EqualTo(expectedMultiplier).Within(Precision.DOUBLE_EPSILON));
|
||||
|
||||
var calculator = Ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext());
|
||||
Assert.That(calculator.CalculateFor(mods), Is.EqualTo(expectedMultiplier).Within(Precision.DOUBLE_EPSILON));
|
||||
});
|
||||
var calculator = Ruleset.CreateScoreMultiplierCalculator(new ScoreMultiplierContext(new BeatmapDifficulty()));
|
||||
Assert.That(calculator.CalculateFor(mods), Is.EqualTo(expectedMultiplier).Within(Precision.DOUBLE_EPSILON));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="20.1.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2026.521.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2026.527.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2026.523.0" />
|
||||
<PackageReference Include="Sentry" Version="6.2.0" />
|
||||
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user