Merge branch 'master' into correct-trail-animation-frame

This commit is contained in:
Dean Herbert 2020-03-13 09:55:41 +09:00 committed by GitHub
commit c30bfa79e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
118 changed files with 1560 additions and 692 deletions

View File

@ -52,6 +52,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.304.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2020.304.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.310.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2020.312.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,54 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Catch.Tests.Mods
{
public class TestSceneCatchModPerfect : ModPerfectTestScene
{
public TestSceneCatchModPerfect()
: base(new CatchRuleset(), new CatchModPerfect())
{
}
[TestCase(false)]
[TestCase(true)]
public void TestBananaShower(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new BananaShower { StartTime = 1000, EndTime = 3000 }, false), shouldMiss);
[TestCase(false)]
[TestCase(true)]
public void TestFruit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Fruit { StartTime = 1000 }), shouldMiss);
[TestCase(false)]
[TestCase(true)]
public void TestJuiceStream(bool shouldMiss)
{
var stream = new JuiceStream
{
StartTime = 1000,
Path = new SliderPath(PathType.Linear, new[]
{
Vector2.Zero,
new Vector2(100, 0),
})
};
CreateHitObjectTest(new HitObjectTestData(stream), shouldMiss);
}
// We only care about testing misses, hits are tested via JuiceStream
[TestCase(true)]
public void TestDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Droplet { StartTime = 1000 }), shouldMiss);
// We only care about testing misses, hits are tested via JuiceStream
[TestCase(true)]
public void TestTinyDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new TinyDroplet { StartTime = 1000 }), shouldMiss);
}
}

View File

@ -18,7 +18,9 @@ namespace osu.Game.Rulesets.Catch.Tests
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
typeof(BananaShower), typeof(BananaShower),
typeof(Banana),
typeof(DrawableBananaShower), typeof(DrawableBananaShower),
typeof(DrawableBanana),
typeof(CatchRuleset), typeof(CatchRuleset),
typeof(DrawableCatchRuleset), typeof(DrawableCatchRuleset),

View File

@ -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 System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -28,11 +26,6 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
private RulesetInfo catchRuleset; private RulesetInfo catchRuleset;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(CatcherArea),
};
public TestSceneCatcherArea() public TestSceneCatcherArea()
{ {
AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher); AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher);

View File

@ -4,7 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -34,8 +34,8 @@ namespace osu.Game.Rulesets.Catch.Tests
private DrawableCatchRuleset drawableRuleset; private DrawableCatchRuleset drawableRuleset;
private double playfieldTime => drawableRuleset.Playfield.Time.Current; private double playfieldTime => drawableRuleset.Playfield.Time.Current;
[BackgroundDependencyLoader] [SetUp]
private void load() public void Setup() => Schedule(() =>
{ {
var controlPointInfo = new ControlPointInfo(); var controlPointInfo = new ControlPointInfo();
controlPointInfo.Add(0, new TimingControlPoint()); controlPointInfo.Add(0, new TimingControlPoint());
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Catch.Tests
ControlPointInfo = controlPointInfo ControlPointInfo = controlPointInfo
}); });
Add(new Container Child = new Container
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -66,16 +66,49 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
drawableRuleset = new DrawableCatchRuleset(new CatchRuleset(), beatmap.GetPlayableBeatmap(new CatchRuleset().RulesetInfo)) drawableRuleset = new DrawableCatchRuleset(new CatchRuleset(), beatmap.GetPlayableBeatmap(new CatchRuleset().RulesetInfo))
} }
}); };
});
[Test]
public void TestFruits()
{
AddStep("hit fruits", () => spawnFruits(true));
AddUntilStep("wait for completion", () => playfieldIsEmpty);
AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
AddStep("miss fruits", () => spawnFruits()); AddStep("miss fruits", () => spawnFruits());
AddStep("hit fruits", () => spawnFruits(true)); AddUntilStep("wait for completion", () => playfieldIsEmpty);
AddStep("miss juicestream", () => spawnJuiceStream()); AddAssert("catcher state is failed", () => catcherState == CatcherAnimationState.Fail);
AddStep("hit juicestream", () => spawnJuiceStream(true));
AddStep("miss bananas", () => spawnBananas());
AddStep("hit bananas", () => spawnBananas(true));
} }
[Test]
public void TestJuicestream()
{
AddStep("hit juicestream", () => spawnJuiceStream(true));
AddUntilStep("wait for completion", () => playfieldIsEmpty);
AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
AddStep("miss juicestream", () => spawnJuiceStream());
AddUntilStep("wait for completion", () => playfieldIsEmpty);
AddAssert("catcher state is failed", () => catcherState == CatcherAnimationState.Fail);
}
[Test]
public void TestBananas()
{
AddStep("hit bananas", () => spawnBananas(true));
AddUntilStep("wait for completion", () => playfieldIsEmpty);
AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
AddStep("miss bananas", () => spawnBananas());
AddUntilStep("wait for completion", () => playfieldIsEmpty);
AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
}
private bool playfieldIsEmpty => !((CatchPlayfield)drawableRuleset.Playfield).AllHitObjects.Any(h => h.IsAlive);
private CatcherAnimationState catcherState => ((CatchPlayfield)drawableRuleset.Playfield).CatcherArea.MovableCatcher.CurrentState;
private void spawnFruits(bool hit = false) private void spawnFruits(bool hit = false)
{ {
for (int i = 1; i <= 4; i++) for (int i = 1; i <= 4; i++)

View File

@ -2,19 +2,27 @@
// 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 System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
public class TestSceneHyperDash : PlayerTestScene public class TestSceneHyperDash : PlayerTestScene
{ {
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(CatcherArea),
};
public TestSceneHyperDash() public TestSceneHyperDash()
: base(new CatchRuleset()) : base(new CatchRuleset())
{ {
@ -26,9 +34,11 @@ namespace osu.Game.Rulesets.Catch.Tests
public void TestHyperDash() public void TestHyperDash()
{ {
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash); AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing); AddUntilStep("wait for right movement", () => getCatcher().Scale.X > 0); // don't check hyperdashing as it happens too fast.
for (int i = 0; i < 2; i++) AddUntilStep("wait for left movement", () => getCatcher().Scale.X < 0);
for (int i = 0; i < 3; i++)
{ {
AddUntilStep("wait for right hyperdash", () => getCatcher().Scale.X > 0 && getCatcher().HyperDashing); AddUntilStep("wait for right hyperdash", () => getCatcher().Scale.X > 0 && getCatcher().HyperDashing);
AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing); AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing);
@ -49,39 +59,51 @@ namespace osu.Game.Rulesets.Catch.Tests
}; };
// Should produce a hyper-dash (edge case test) // Should produce a hyper-dash (edge case test)
beatmap.HitObjects.Add(new Fruit { StartTime = 1816, X = 308 / 512f, NewCombo = true }); beatmap.HitObjects.Add(new Fruit { StartTime = 1816, X = 56 / 512f, NewCombo = true });
beatmap.HitObjects.Add(new JuiceStream { StartTime = 2008, X = 56 / 512f, }); beatmap.HitObjects.Add(new Fruit { StartTime = 2008, X = 308 / 512f, NewCombo = true });
double startTime = 3000; double startTime = 3000;
const float left_x = 0.02f; const float left_x = 0.02f;
const float right_x = 0.98f; const float right_x = 0.98f;
createObjects(() => new Fruit(), left_x); createObjects(() => new Fruit { X = left_x });
createObjects(() => new JuiceStream(), right_x); createObjects(() => new TestJuiceStream(right_x), 1);
createObjects(() => new JuiceStream(), left_x); createObjects(() => new TestJuiceStream(left_x), 1);
createObjects(() => new Fruit(), right_x); createObjects(() => new Fruit { X = right_x });
createObjects(() => new Fruit(), left_x); createObjects(() => new Fruit { X = left_x });
createObjects(() => new Fruit(), right_x); createObjects(() => new Fruit { X = right_x });
createObjects(() => new JuiceStream(), left_x); createObjects(() => new TestJuiceStream(left_x), 1);
return beatmap; return beatmap;
void createObjects(Func<CatchHitObject> createObject, float x) void createObjects(Func<CatchHitObject> createObject, int count = 3)
{ {
const float spacing = 140; const float spacing = 140;
for (int i = 0; i < 3; i++) for (int i = 0; i < count; i++)
{ {
var hitObject = createObject(); var hitObject = createObject();
hitObject.X = x;
hitObject.StartTime = startTime + i * spacing; hitObject.StartTime = startTime + i * spacing;
beatmap.HitObjects.Add(hitObject); beatmap.HitObjects.Add(hitObject);
} }
startTime += 700; startTime += 700;
} }
} }
private class TestJuiceStream : JuiceStream
{
public TestJuiceStream(float x)
{
X = x;
Path = new SliderPath(new[]
{
new PathControlPoint(Vector2.Zero),
new PathControlPoint(new Vector2(30, 0)),
});
}
}
} }
} }

View File

@ -28,8 +28,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
ApplyPositionOffsets(Beatmap); ApplyPositionOffsets(Beatmap);
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
int index = 0; int index = 0;
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>()) foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
@ -76,6 +74,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
break; break;
case JuiceStream juiceStream: case JuiceStream juiceStream:
// Todo: BUG!! Stable used the last control point as the final position of the path, but it should use the computed path instead.
lastPosition = juiceStream.X + juiceStream.Path.ControlPoints[^1].Position.Value.X / CatchPlayfield.BASE_WIDTH;
// Todo: BUG!! Stable attempted to use the end time of the stream, but referenced it too early in execution and used the start time instead.
lastStartTime = juiceStream.StartTime;
foreach (var nested in juiceStream.NestedHitObjects) foreach (var nested in juiceStream.NestedHitObjects)
{ {
var catchObject = (CatchHitObject)nested; var catchObject = (CatchHitObject)nested;
@ -90,20 +94,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
break; break;
} }
} }
initialiseHyperDash(beatmap);
} }
private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng) private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng)
{ {
if (hitObject is JuiceStream stream)
{
lastPosition = stream.EndX;
lastStartTime = stream.EndTime;
return;
}
if (!(hitObject is Fruit))
return;
float offsetPosition = hitObject.X; float offsetPosition = hitObject.X;
double startTime = hitObject.StartTime; double startTime = hitObject.StartTime;
@ -116,7 +112,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
} }
float positionDiff = offsetPosition - lastPosition.Value; float positionDiff = offsetPosition - lastPosition.Value;
double timeDiff = startTime - lastStartTime;
// Todo: BUG!! Stable calculated time deltas as ints, which affects randomisation. This should be changed to a double.
int timeDiff = (int)(startTime - lastStartTime);
if (timeDiff > 1000) if (timeDiff > 1000)
{ {
@ -132,7 +130,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
return; return;
} }
if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d) // ReSharper disable once PossibleLossOfFraction
if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3)
applyOffset(ref offsetPosition, positionDiff); applyOffset(ref offsetPosition, positionDiff);
hitObject.XOffset = offsetPosition - hitObject.X; hitObject.XOffset = offsetPosition - hitObject.X;
@ -191,14 +190,14 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
} }
} }
private void initialiseHyperDash(List<CatchHitObject> objects) private static void initialiseHyperDash(IBeatmap beatmap)
{ {
List<CatchHitObject> objectWithDroplets = new List<CatchHitObject>(); List<CatchHitObject> objectWithDroplets = new List<CatchHitObject>();
foreach (var currentObject in objects) foreach (var currentObject in beatmap.HitObjects)
{ {
if (currentObject is Fruit) if (currentObject is Fruit fruitObject)
objectWithDroplets.Add(currentObject); objectWithDroplets.Add(fruitObject);
if (currentObject is JuiceStream) if (currentObject is JuiceStream)
{ {
@ -212,7 +211,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
double halfCatcherWidth = CatcherArea.GetCatcherSize(Beatmap.BeatmapInfo.BaseDifficulty) / 2; double halfCatcherWidth = CatcherArea.GetCatcherSize(beatmap.BeatmapInfo.BaseDifficulty) / 2;
int lastDirection = 0; int lastDirection = 0;
double lastExcess = halfCatcherWidth; double lastExcess = halfCatcherWidth;
@ -221,6 +220,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
CatchHitObject currentObject = objectWithDroplets[i]; CatchHitObject currentObject = objectWithDroplets[i];
CatchHitObject nextObject = objectWithDroplets[i + 1]; CatchHitObject nextObject = objectWithDroplets[i + 1];
// Reset variables in-case values have changed (e.g. after applying HR)
currentObject.HyperDashTarget = null;
currentObject.DistanceToHyperDash = 0;
int thisDirection = nextObject.X > currentObject.X ? 1 : -1; int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable
double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth); double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);

View File

@ -1,11 +1,17 @@
// 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.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModPerfect : ModPerfect public class CatchModPerfect : ModPerfect
{ {
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
=> !(result.Judgement is CatchBananaJudgement)
&& base.FailCondition(healthProcessor, result);
} }
} }

View File

@ -2,6 +2,7 @@
// 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.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Utils; using osu.Framework.Utils;
using osuTK.Graphics; using osuTK.Graphics;
@ -22,6 +23,23 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
return colour ??= getBananaColour(); return colour ??= getBananaColour();
} }
protected override void UpdateInitialTransforms()
{
base.UpdateInitialTransforms();
const float end_scale = 0.6f;
const float random_scale_range = 1.6f;
ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RNG.NextSingle()))
.Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt);
ScaleContainer.RotateTo(getRandomAngle())
.Then()
.RotateTo(getRandomAngle(), HitObject.TimePreempt);
float getRandomAngle() => 180 * (RNG.NextSingle() * 2 - 1);
}
private Color4 getBananaColour() private Color4 getBananaColour()
{ {
switch (RNG.Next(0, 3)) switch (RNG.Next(0, 3))

View File

@ -91,10 +91,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss); ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
} }
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
protected override void UpdateInitialTransforms() => this.FadeInFromZero(200);
protected override void UpdateStateTransforms(ArmedState state) protected override void UpdateStateTransforms(ArmedState state)
{ {
var endTime = HitObject.GetEndTime(); var endTime = HitObject.GetEndTime();

View File

@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
float startRotation = RNG.NextSingle() * 20; float startRotation = RNG.NextSingle() * 20;
double duration = HitObject.TimePreempt + 2000; double duration = HitObject.TimePreempt + 2000;
this.RotateTo(startRotation).RotateTo(startRotation + 720, duration); ScaleContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
} }
} }
} }

View File

@ -13,7 +13,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
public DrawableFruit(Fruit h) public DrawableFruit(Fruit h)
: base(h) : base(h)
{ {
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -21,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{ {
ScaleContainer.Child = new SkinnableDrawable( ScaleContainer.Child = new SkinnableDrawable(
new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece()); new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece());
ScaleContainer.Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
} }
private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation) private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation)

View File

@ -6,6 +6,7 @@ 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 osuTK;
namespace osu.Game.Rulesets.Catch.Objects.Drawables namespace osu.Game.Rulesets.Catch.Objects.Drawables
{ {
@ -14,11 +15,13 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
private readonly Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation; private readonly Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation;
private readonly Container dropletContainer; private readonly Container dropletContainer;
public override Vector2 OriginPosition => base.OriginPosition - new Vector2(0, CatchHitObject.OBJECT_RADIUS);
public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null) public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null)
: base(s) : base(s)
{ {
this.createDrawableRepresentation = createDrawableRepresentation; this.createDrawableRepresentation = createDrawableRepresentation;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.X;
Origin = Anchor.BottomLeft; Origin = Anchor.BottomLeft;
X = 0; X = 0;
@ -27,6 +30,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
protected override void AddNestedHitObject(DrawableHitObject hitObject) protected override void AddNestedHitObject(DrawableHitObject hitObject)
{ {
hitObject.Origin = Anchor.BottomCentre;
base.AddNestedHitObject(hitObject); base.AddNestedHitObject(hitObject);
dropletContainer.Add(hitObject); dropletContainer.Add(hitObject);
} }

View File

@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Catch.Objects
public int RepeatCount { get; set; } public int RepeatCount { get; set; }
public double Velocity; public double Velocity { get; private set; }
public double TickDistance; public double TickDistance { get; private set; }
/// <summary> /// <summary>
/// The length of one span of this <see cref="JuiceStream"/>. /// The length of one span of this <see cref="JuiceStream"/>.
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Objects
{ {
base.CreateNestedHitObjects(); base.CreateNestedHitObjects();
var tickSamples = Samples.Select(s => new HitSampleInfo var dropletSamples = Samples.Select(s => new HitSampleInfo
{ {
Bank = s.Bank, Bank = s.Bank,
Name = @"slidertick", Name = @"slidertick",
@ -75,7 +75,6 @@ namespace osu.Game.Rulesets.Catch.Objects
{ {
AddNested(new TinyDroplet AddNested(new TinyDroplet
{ {
Samples = tickSamples,
StartTime = t + lastEvent.Value.Time, StartTime = t + lastEvent.Value.Time,
X = X + Path.PositionAt( X = X + Path.PositionAt(
lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH, lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH,
@ -93,7 +92,7 @@ namespace osu.Game.Rulesets.Catch.Objects
case SliderEventType.Tick: case SliderEventType.Tick:
AddNested(new Droplet AddNested(new Droplet
{ {
Samples = tickSamples, Samples = dropletSamples,
StartTime = e.Time, StartTime = e.Time,
X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH, X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH,
}); });

View File

@ -188,7 +188,7 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
currentCatcher?.Hide(); currentCatcher?.Hide();
switch (currentState) switch (CurrentState)
{ {
default: default:
currentCatcher = catcherIdle; currentCatcher = catcherIdle;
@ -263,16 +263,14 @@ namespace osu.Game.Rulesets.Catch.UI
Position = Position Position = Position
}; };
AdditiveTarget?.Add(additive);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
additive.Expire(true); additive.Expire(true);
AdditiveTarget?.Add(additive);
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
} }
private Drawable createCatcherSprite() => new CatcherSprite(currentState);
/// <summary> /// <summary>
/// Add a caught fruit to the catcher's stack. /// Add a caught fruit to the catcher's stack.
/// </summary> /// </summary>
@ -341,7 +339,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (validCatch) if (validCatch)
updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle);
else else if (!(fruit is Banana))
updateState(CatcherAnimationState.Fail); updateState(CatcherAnimationState.Fail);
return validCatch; return validCatch;
@ -349,14 +347,14 @@ namespace osu.Game.Rulesets.Catch.UI
private void updateState(CatcherAnimationState state) private void updateState(CatcherAnimationState state)
{ {
if (currentState == state) if (CurrentState == state)
return; return;
currentState = state; CurrentState = state;
updateCatcher(); updateCatcher();
} }
private CatcherAnimationState currentState; public CatcherAnimationState CurrentState { get; private set; }
private double hyperDashModifier = 1; private double hyperDashModifier = 1;
private int hyperDashDirection; private int hyperDashDirection;
@ -376,14 +374,14 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
const float hyper_dash_transition_length = 180; const float hyper_dash_transition_length = 180;
bool previouslyHyperDashing = HyperDashing; bool wasHyperDashing = HyperDashing;
if (modifier <= 1 || X == targetPosition) if (modifier <= 1 || X == targetPosition)
{ {
hyperDashModifier = 1; hyperDashModifier = 1;
hyperDashDirection = 0; hyperDashDirection = 0;
if (previouslyHyperDashing) if (wasHyperDashing)
{ {
this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint); this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint); this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint);
@ -396,11 +394,18 @@ namespace osu.Game.Rulesets.Catch.UI
hyperDashDirection = Math.Sign(targetPosition - X); hyperDashDirection = Math.Sign(targetPosition - X);
hyperDashTargetPosition = targetPosition; hyperDashTargetPosition = targetPosition;
if (!previouslyHyperDashing) if (!wasHyperDashing)
{ {
this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint); this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint); this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
Trail = true; Trail = true;
var hyperDashEndGlow = createAdditiveSprite(true);
hyperDashEndGlow.MoveToOffset(new Vector2(0, -20), 1200, Easing.In);
hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.9f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In);
hyperDashEndGlow.FadeOut(1200);
hyperDashEndGlow.Expire(true);
} }
} }
} }

View File

@ -0,0 +1,26 @@
// 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 NUnit.Framework;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests.Mods
{
public class TestSceneManiaModPerfect : ModPerfectTestScene
{
public TestSceneManiaModPerfect()
: base(new ManiaRuleset(), new ManiaModPerfect())
{
}
[TestCase(false)]
[TestCase(true)]
public void TestNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Note { StartTime = 1000 }), shouldMiss);
[TestCase(false)]
[TestCase(true)]
public void TestHoldNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new HoldNote { StartTime = 1000, EndTime = 3000 }), shouldMiss);
}
}

View File

@ -0,0 +1,52 @@
// 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 NUnit.Framework;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests.Mods
{
public class TestSceneOsuModPerfect : ModPerfectTestScene
{
public TestSceneOsuModPerfect()
: base(new OsuRuleset(), new OsuModPerfect())
{
}
[TestCase(false)]
[TestCase(true)]
public void TestHitCircle(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new HitCircle { StartTime = 1000 }), shouldMiss);
[TestCase(false)]
[TestCase(true)]
public void TestSlider(bool shouldMiss)
{
var slider = new Slider
{
StartTime = 1000,
Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(100, 0), })
};
CreateHitObjectTest(new HitObjectTestData(slider), shouldMiss);
}
[TestCase(false)]
[TestCase(true)]
public void TestSpinner(bool shouldMiss)
{
var spinner = new Spinner
{
StartTime = 1000,
EndTime = 3000,
Position = new Vector2(256, 192)
};
CreateHitObjectTest(new HitObjectTestData(spinner), shouldMiss);
}
}
}

View File

@ -0,0 +1,101 @@
// 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 NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Replays;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Tests.Visual;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneMissHitWindowJudgements : ModTestScene
{
public TestSceneMissHitWindowJudgements()
: base(new OsuRuleset())
{
}
[Test]
public void TestMissViaEarlyHit()
{
var beatmap = new Beatmap
{
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
};
var hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
CreateModTest(new ModTestData
{
Autoplay = false,
Mod = new TestAutoMod(),
Beatmap = new Beatmap
{
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
},
PassCondition = () => Player.Results.Count > 0 && Player.Results[0].TimeOffset < -hitWindows.WindowFor(HitResult.Meh) && Player.Results[0].Type == HitResult.Miss
});
}
[Test]
public void TestMissViaNotHitting()
{
var beatmap = new Beatmap
{
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
};
var hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
CreateModTest(new ModTestData
{
Autoplay = false,
Beatmap = beatmap,
PassCondition = () => Player.Results.Count > 0 && Player.Results[0].TimeOffset >= hitWindows.WindowFor(HitResult.Meh) && Player.Results[0].Type == HitResult.Miss
});
}
private class TestAutoMod : OsuModAutoplay
{
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
{
ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } },
Replay = new MissingAutoGenerator(beatmap).Generate()
};
}
private class MissingAutoGenerator : OsuAutoGeneratorBase
{
public new OsuBeatmap Beatmap => (OsuBeatmap)base.Beatmap;
public MissingAutoGenerator(IBeatmap beatmap)
: base(beatmap)
{
}
public override Replay Generate()
{
AddFrameToReplay(new OsuReplayFrame(-100000, new Vector2(256, 500)));
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 1500, new Vector2(256, 500)));
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 1500, new Vector2(256, 500)));
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 450, Beatmap.HitObjects[0].StackedPosition));
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 350, Beatmap.HitObjects[0].StackedPosition, OsuAction.LeftButton));
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 325, Beatmap.HitObjects[0].StackedPosition));
return Replay;
}
}
}
}

View File

@ -36,8 +36,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly SpriteIcon symbol; private readonly SpriteIcon symbol;
private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c"); private readonly Color4 baseColour = Color4Extensions.FromHex(@"002c3c");
private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c"); private readonly Color4 fillColour = Color4Extensions.FromHex(@"005b7c");
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
new DifficultyRange(HitResult.Great, 80, 50, 20), new DifficultyRange(HitResult.Great, 80, 50, 20),
new DifficultyRange(HitResult.Good, 140, 100, 60), new DifficultyRange(HitResult.Good, 140, 100, 60),
new DifficultyRange(HitResult.Meh, 200, 150, 100), new DifficultyRange(HitResult.Meh, 200, 150, 100),
new DifficultyRange(HitResult.Miss, 200, 200, 200), new DifficultyRange(HitResult.Miss, 400, 400, 400),
}; };
public override bool IsHitResultAllowed(HitResult result) public override bool IsHitResultAllowed(HitResult result)

View File

@ -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 NUnit.Framework;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Scoring;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Taiko.Tests.Mods
{
public class TestSceneTaikoModPerfect : ModPerfectTestScene
{
public TestSceneTaikoModPerfect()
: base(new TestTaikoRuleset(), new TaikoModPerfect())
{
}
[TestCase(false)]
[TestCase(true)]
public void TestHit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new CentreHit { StartTime = 1000 }), shouldMiss);
[TestCase(false)]
[TestCase(true)]
public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new DrumRoll { StartTime = 1000, EndTime = 3000 }), shouldMiss);
[TestCase(false)]
[TestCase(true)]
public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }), shouldMiss);
private class TestTaikoRuleset : TaikoRuleset
{
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new TestTaikoHealthProcessor();
private class TestTaikoHealthProcessor : TaikoHealthProcessor
{
protected override void Reset(bool storeResults)
{
base.Reset(storeResults);
Health.Value = 1; // Don't care about the health condition (only the mod condition)
}
}
}
}
}

View File

@ -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 System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
@ -39,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
{ {
base.ApplyBeatmap(beatmap); base.ApplyBeatmap(beatmap);
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType<Hit>().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType<Hit>().Count()) * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120); hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
} }

View File

@ -99,7 +99,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
var storyboard = decoder.Decode(stream); var storyboard = decoder.Decode(stream);
StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3);
Assert.AreEqual(123456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X); Assert.AreEqual(3456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X);
} }
} }
} }

View File

@ -1,5 +1,5 @@
[Variables] [Variables]
$var=1234 $var=34
[Events] [Events]
Sprite,Background,TopCentre,"img.jpg",$var56,240 Sprite,Background,TopCentre,"img.jpg",$var56,240

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Menus
API.LocalUser.Value = new User API.LocalUser.Value = new User
{ {
Username = API.LocalUser.Value.Username, Username = API.LocalUser.Value.Username,
Id = API.LocalUser.Value.Id, Id = API.LocalUser.Value.Id + 1,
IsSupporter = !API.LocalUser.Value.IsSupporter, IsSupporter = !API.LocalUser.Value.IsSupporter,
}; };
}); });

View File

@ -17,8 +17,8 @@ namespace osu.Game.Tests.Visual.Online
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
typeof(UpdateStreamBadgeArea), typeof(ChangelogUpdateStreamControl),
typeof(UpdateStreamBadge), typeof(ChangelogUpdateStreamItem),
typeof(ChangelogHeader), typeof(ChangelogHeader),
typeof(ChangelogContent), typeof(ChangelogContent),
typeof(ChangelogListing), typeof(ChangelogListing),

View File

@ -7,6 +7,7 @@ using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -102,7 +103,7 @@ namespace osu.Game.Tests.Visual.Online
{ {
bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour); bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour);
Color4 textColour = isAction && hasBackground ? OsuColour.FromHex(newLine.Message.Sender.Colour) : Color4.White; Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White;
var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList(); var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts); var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);

View File

@ -497,7 +497,7 @@ namespace osu.Game.Tests.Visual.SongSelect
} }
bool changed = false; bool changed = false;
AddStep($"Load {beatmapSets.Count} Beatmaps", () => AddStep($"Load {(beatmapSets.Count > 0 ? beatmapSets.Count.ToString() : "some")} beatmaps", () =>
{ {
carousel.Filter(new FilterCriteria()); carousel.Filter(new FilterCriteria());
carousel.BeatmapSetsChanged = () => changed = true; carousel.BeatmapSetsChanged = () => changed = true;
@ -697,6 +697,8 @@ namespace osu.Game.Tests.Visual.SongSelect
public new List<DrawableCarouselItem> Items => base.Items; public new List<DrawableCarouselItem> Items => base.Items;
public bool PendingFilterTask => PendingFilter != null; public bool PendingFilterTask => PendingFilter != null;
protected override IEnumerable<BeatmapSetInfo> GetLoadableBeatmaps() => Enumerable.Empty<BeatmapSetInfo>();
} }
} }
} }

View File

@ -465,6 +465,43 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmap.OnlineBeatmapID == target.OnlineBeatmapID); AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmap.OnlineBeatmapID == target.OnlineBeatmapID);
} }
[Test]
public void TestExternalBeatmapChangeWhileFilteredThenRefilter()
{
createSongSelect();
addManyTestMaps();
changeRuleset(0);
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nonono");
AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap);
AddUntilStep("has no selection", () => songSelect.Carousel.SelectedBeatmap == null);
BeatmapInfo target = null;
AddStep("select beatmap externally", () =>
{
target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == 1))
.ElementAt(5).Beatmaps.First();
Beatmap.Value = manager.GetWorkingBeatmap(target);
});
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmap?.OnlineBeatmapID == target.OnlineBeatmapID);
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nononoo");
AddUntilStep("game lost selection", () => Beatmap.Value is DummyWorkingBeatmap);
AddAssert("carousel lost selection", () => songSelect.Carousel.SelectedBeatmap == null);
}
[Test] [Test]
public void TestAutoplayViaCtrlEnter() public void TestAutoplayViaCtrlEnter()
{ {

View File

@ -0,0 +1,63 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Overlays;
using osu.Game.Overlays.Home.Friends;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneFriendsOnlineStatusControl : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(FriendsOnlineStatusControl),
typeof(FriendsOnlineStatusItem),
typeof(OverlayStreamControl<>),
typeof(OverlayStreamItem<>),
typeof(FriendsBundle)
};
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
private FriendsOnlineStatusControl control;
[SetUp]
public void SetUp() => Schedule(() => Child = control = new FriendsOnlineStatusControl
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
[Test]
public void Populate()
{
AddStep("Populate", () => control.Populate(new List<User>
{
new User
{
IsOnline = true
},
new User
{
IsOnline = false
},
new User
{
IsOnline = false
}
}));
AddAssert("3 users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.All)?.Count == 3);
AddAssert("1 online user", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Online)?.Count == 1);
AddAssert("2 offline users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Offline)?.Count == 2);
}
}
}

View File

@ -0,0 +1,42 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Screens.Gameplay.Components;
using osuTK;
namespace osu.Game.Tournament.Tests.Components
{
public class TestSceneMatchHeader : TournamentTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(DrawableTournamentHeaderText),
typeof(DrawableTournamentHeaderLogo),
};
public TestSceneMatchHeader()
{
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(50),
Children = new Drawable[]
{
new TournamentSpriteText { Text = "with logo", Font = OsuFont.Torus.With(size: 30) },
new MatchHeader(),
new TournamentSpriteText { Text = "without logo", Font = OsuFont.Torus.With(size: 30) },
new MatchHeader { ShowLogo = false },
new TournamentSpriteText { Text = "without scores", Font = OsuFont.Torus.With(size: 30) },
new MatchHeader { ShowScores = false },
}
};
}
}
}

View File

@ -0,0 +1,37 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Tournament.Components
{
public class DrawableTournamentHeaderLogo : CompositeDrawable
{
public DrawableTournamentHeaderLogo()
{
InternalChild = new LogoSprite();
Height = 82;
RelativeSizeAxes = Axes.X;
}
private class LogoSprite : Sprite
{
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
RelativeSizeAxes = Axes.Both;
FillMode = FillMode.Fit;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Texture = textures.Get("header-logo");
}
}
}
}

View File

@ -0,0 +1,37 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Tournament.Components
{
public class DrawableTournamentHeaderText : CompositeDrawable
{
public DrawableTournamentHeaderText()
{
InternalChild = new TextSprite();
Height = 22;
RelativeSizeAxes = Axes.X;
}
private class TextSprite : Sprite
{
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
RelativeSizeAxes = Axes.Both;
FillMode = FillMode.Fit;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Texture = textures.Get("header-text");
}
}
}
}

View File

@ -1,16 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Graphics;
namespace osu.Game.Tournament.Components
{
public class DrawableTournamentTitleText : TournamentSpriteText
{
public DrawableTournamentTitleText()
{
Text = "osu!taiko world cup 2020";
Font = OsuFont.Torus.With(size: 26, weight: FontWeight.SemiBold);
}
}
}

View File

@ -22,7 +22,7 @@ namespace osu.Game.Tournament.Components
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
new DrawableTournamentTitleText(), new DrawableTournamentHeaderText(),
new TournamentSpriteText new TournamentSpriteText
{ {
Text = match.Round.Value?.Name.Value ?? "Unknown Round", Text = match.Round.Value?.Name.Value ?? "Unknown Round",

View File

@ -84,7 +84,7 @@ namespace osu.Game.Tournament.Components
// else if (info.CurrentMatch.Value.Team2.Value.Players.Any(u => u.Id == Message.Sender.Id)) // else if (info.CurrentMatch.Value.Team2.Value.Players.Any(u => u.Id == Message.Sender.Id))
// SenderText.Colour = TournamentGame.COLOUR_BLUE; // SenderText.Colour = TournamentGame.COLOUR_BLUE;
// else if (Message.Sender.Colour != null) // else if (Message.Sender.Colour != null)
// SenderText.Colour = ColourBox.Colour = OsuColour.FromHex(Message.Sender.Colour); // SenderText.Colour = ColourBox.Colour = Color4Extensions.FromHex(Message.Sender.Colour);
} }
} }
} }

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Video; using osu.Framework.Graphics.Video;
using osu.Framework.Platform;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -28,13 +27,13 @@ namespace osu.Game.Tournament.Components
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(Storage storage) private void load(TournamentStorage storage)
{ {
var stream = storage.GetStream($@"videos/{filename}.m4v"); var stream = storage.GetStream($@"videos/{filename}");
if (stream != null) if (stream != null)
{ {
InternalChild = video = new VideoSprite(stream) InternalChild = video = new VideoSprite(stream, false)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit, FillMode = FillMode.Fit,

View File

@ -163,12 +163,7 @@ namespace osu.Game.Tournament.IPC
{ {
try try
{ {
stableInstallPath = "G:\\My Drive\\Main\\osu!tourney"; stableInstallPath = Environment.GetEnvironmentVariable("OSU_STABLE_PATH");
if (checkExists(stableInstallPath))
return stableInstallPath;
stableInstallPath = "G:\\My Drive\\Main\\osu!mappool";
if (checkExists(stableInstallPath)) if (checkExists(stableInstallPath))
return stableInstallPath; return stableInstallPath;

View File

@ -2,14 +2,11 @@
// 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.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.Input.Events;
using osu.Game.Tournament.Components; using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models; using osu.Game.Tournament.Models;
using osuTK; using osuTK;
using osuTK.Input;
namespace osu.Game.Tournament.Screens.Gameplay.Components namespace osu.Game.Tournament.Screens.Gameplay.Components
{ {
@ -17,13 +14,39 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
{ {
private TeamScoreDisplay teamDisplay1; private TeamScoreDisplay teamDisplay1;
private TeamScoreDisplay teamDisplay2; private TeamScoreDisplay teamDisplay2;
private DrawableTournamentHeaderLogo logo;
private bool showScores = true;
public bool ShowScores public bool ShowScores
{ {
get => showScores;
set set
{ {
teamDisplay1.ShowScore = value; if (value == showScores)
teamDisplay2.ShowScore = value; return;
showScores = value;
if (IsLoaded)
updateDisplay();
}
}
private bool showLogo = true;
public bool ShowLogo
{
get => showLogo;
set
{
if (value == showLogo)
return;
showLogo = value;
if (IsLoaded)
updateDisplay();
} }
} }
@ -38,19 +61,25 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Padding = new MarginPadding(20),
Spacing = new Vector2(5), Spacing = new Vector2(5),
Children = new Drawable[] Children = new Drawable[]
{ {
new DrawableTournamentTitleText logo = new DrawableTournamentHeaderLogo
{ {
Anchor = Anchor.Centre, Anchor = Anchor.TopCentre,
Origin = Anchor.Centre, Origin = Anchor.TopCentre,
Scale = new Vector2(1.2f) Alpha = showLogo ? 1 : 0
}, },
new RoundDisplay new DrawableTournamentHeaderText
{ {
Anchor = Anchor.Centre, Anchor = Anchor.TopCentre,
Origin = Anchor.Centre, Origin = Anchor.TopCentre,
},
new MatchRoundDisplay
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Scale = new Vector2(0.4f) Scale = new Vector2(0.4f)
}, },
} }
@ -66,76 +95,16 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
}, },
}; };
}
}
public class TeamScoreDisplay : CompositeDrawable updateDisplay();
{
private readonly TeamColour teamColour;
private readonly Bindable<TournamentMatch> currentMatch = new Bindable<TournamentMatch>();
private readonly Bindable<TournamentTeam> currentTeam = new Bindable<TournamentTeam>();
private readonly Bindable<int?> currentTeamScore = new Bindable<int?>();
private TeamDisplay teamDisplay;
public bool ShowScore { set => teamDisplay.ShowScore = value; }
public TeamScoreDisplay(TeamColour teamColour)
{
this.teamColour = teamColour;
RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X;
} }
[BackgroundDependencyLoader] private void updateDisplay()
private void load(LadderInfo ladder)
{ {
currentMatch.BindTo(ladder.CurrentMatch); teamDisplay1.ShowScore = showScores;
currentMatch.BindValueChanged(matchChanged, true); teamDisplay2.ShowScore = showScores;
}
private void matchChanged(ValueChangedEvent<TournamentMatch> match) logo.Alpha = showLogo ? 1 : 0;
{
currentTeamScore.UnbindBindings();
currentTeam.UnbindBindings();
if (match.NewValue != null)
{
currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score);
currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2);
}
// team may change to same team, which means score is not in a good state.
// thus we handle this manually.
teamChanged(currentTeam.Value);
}
protected override bool OnMouseDown(MouseDownEvent e)
{
switch (e.Button)
{
case MouseButton.Left:
if (currentTeamScore.Value < currentMatch.Value.PointsToWin)
currentTeamScore.Value++;
return true;
case MouseButton.Right:
if (currentTeamScore.Value > 0)
currentTeamScore.Value--;
return true;
}
return base.OnMouseDown(e);
}
private void teamChanged(TournamentTeam team)
{
InternalChildren = new Drawable[]
{
teamDisplay = new TeamDisplay(team, teamColour, currentTeamScore, currentMatch.Value?.PointsToWin ?? 0),
};
} }
} }
} }

View File

@ -8,7 +8,7 @@ using osu.Game.Tournament.Models;
namespace osu.Game.Tournament.Screens.Gameplay.Components namespace osu.Game.Tournament.Screens.Gameplay.Components
{ {
public class RoundDisplay : TournamentSpriteTextWithBackground public class MatchRoundDisplay : TournamentSpriteTextWithBackground
{ {
private readonly Bindable<TournamentMatch> currentMatch = new Bindable<TournamentMatch>(); private readonly Bindable<TournamentMatch> currentMatch = new Bindable<TournamentMatch>();

View File

@ -11,6 +11,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.IPC; using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models; using osu.Game.Tournament.Models;
using osuTK;
namespace osu.Game.Tournament.Screens.Gameplay.Components namespace osu.Game.Tournament.Screens.Gameplay.Components
{ {
@ -131,13 +132,15 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
Margin = new MarginPadding { Top = bar_height, Horizontal = 10 }; Margin = new MarginPadding { Top = bar_height, Horizontal = 10 };
Winning = false; Winning = false;
DisplayedCountSpriteText.Spacing = new Vector2(-6);
} }
public bool Winning public bool Winning
{ {
set => DisplayedCountSpriteText.Font = value set => DisplayedCountSpriteText.Font = value
? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50) ? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50, fixedWidth: true)
: OsuFont.Torus.With(weight: FontWeight.Regular, size: 40); : OsuFont.Torus.With(weight: FontWeight.Regular, size: 40, fixedWidth: true);
} }
} }
} }

View File

@ -76,7 +76,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
}, },
box = new Box box = new Box
{ {
Colour = OsuColour.FromHex("#FFE8AD"), Colour = Color4Extensions.FromHex("#FFE8AD"),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
}; };
@ -85,7 +85,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Colour = OsuColour.FromHex("#FFE8AD").Opacity(0.1f), Colour = Color4Extensions.FromHex("#FFE8AD").Opacity(0.1f),
Hollow = true, Hollow = true,
Radius = 20, Radius = 20,
Roundness = 10, Roundness = 10,

View File

@ -0,0 +1,83 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Tournament.Models;
using osuTK.Input;
namespace osu.Game.Tournament.Screens.Gameplay.Components
{
public class TeamScoreDisplay : CompositeDrawable
{
private readonly TeamColour teamColour;
private readonly Bindable<TournamentMatch> currentMatch = new Bindable<TournamentMatch>();
private readonly Bindable<TournamentTeam> currentTeam = new Bindable<TournamentTeam>();
private readonly Bindable<int?> currentTeamScore = new Bindable<int?>();
private TeamDisplay teamDisplay;
public bool ShowScore { set => teamDisplay.ShowScore = value; }
public TeamScoreDisplay(TeamColour teamColour)
{
this.teamColour = teamColour;
RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X;
}
[BackgroundDependencyLoader]
private void load(LadderInfo ladder)
{
currentMatch.BindTo(ladder.CurrentMatch);
currentMatch.BindValueChanged(matchChanged, true);
}
private void matchChanged(ValueChangedEvent<TournamentMatch> match)
{
currentTeamScore.UnbindBindings();
currentTeam.UnbindBindings();
if (match.NewValue != null)
{
currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score);
currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2);
}
// team may change to same team, which means score is not in a good state.
// thus we handle this manually.
teamChanged(currentTeam.Value);
}
protected override bool OnMouseDown(MouseDownEvent e)
{
switch (e.Button)
{
case MouseButton.Left:
if (currentTeamScore.Value < currentMatch.Value.PointsToWin)
currentTeamScore.Value++;
return true;
case MouseButton.Right:
if (currentTeamScore.Value > 0)
currentTeamScore.Value--;
return true;
}
return base.OnMouseDown(e);
}
private void teamChanged(TournamentTeam team)
{
InternalChildren = new Drawable[]
{
teamDisplay = new TeamDisplay(team, teamColour, currentTeamScore, currentMatch.Value?.PointsToWin ?? 0),
};
}
}
}

View File

@ -47,7 +47,10 @@ namespace osu.Game.Tournament.Screens.Gameplay
Loop = true, Loop = true,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
header = new MatchHeader(), header = new MatchHeader
{
ShowLogo = false
},
new Container new Container
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,

View File

@ -4,6 +4,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
@ -85,8 +86,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
this.ladderEditor = ladderEditor; this.ladderEditor = ladderEditor;
colourWinner = losers colourWinner = losers
? OsuColour.FromHex("#8E7F48") ? Color4Extensions.FromHex("#8E7F48")
: OsuColour.FromHex("#1462AA"); : Color4Extensions.FromHex("#1462AA");
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
@ -180,8 +181,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{ {
bool winner = completed.Value && isWinner?.Invoke() == true; bool winner = completed.Value && isWinner?.Invoke() == true;
background.FadeColour(winner ? Color4.White : OsuColour.FromHex("#444"), winner ? 500 : 0, Easing.OutQuint); background.FadeColour(winner ? Color4.White : Color4Extensions.FromHex("#444"), winner ? 500 : 0, Easing.OutQuint);
backgroundRight.FadeColour(winner ? colourWinner : OsuColour.FromHex("#333"), winner ? 500 : 0, Easing.OutQuint); backgroundRight.FadeColour(winner ? colourWinner : Color4Extensions.FromHex("#333"), winner ? 500 : 0, Easing.OutQuint);
AcronymText.Colour = winner ? Color4.Black : Color4.White; AcronymText.Colour = winner ? Color4.Black : Color4.White;

View File

@ -32,8 +32,8 @@ namespace osu.Game.Tournament.Screens.Ladder
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, Storage storage) private void load(OsuColour colours, Storage storage)
{ {
normalPathColour = OsuColour.FromHex("#66D1FF"); normalPathColour = Color4Extensions.FromHex("#66D1FF");
losersPathColour = OsuColour.FromHex("#FFC700"); losersPathColour = Color4Extensions.FromHex("#FFC700");
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
@ -47,7 +47,7 @@ namespace osu.Game.Tournament.Screens.Ladder
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Loop = true, Loop = true,
}, },
new DrawableTournamentTitleText new DrawableTournamentHeaderText
{ {
Y = 100, Y = 100,
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,

View File

@ -50,7 +50,7 @@ namespace osu.Game.Tournament.Screens.MapPool
new MatchHeader(), new MatchHeader(),
mapFlows = new FillFlowContainer<FillFlowContainer<TournamentBeatmapPanel>> mapFlows = new FillFlowContainer<FillFlowContainer<TournamentBeatmapPanel>>
{ {
Y = 100, Y = 140,
Spacing = new Vector2(10, 10), Spacing = new Vector2(10, 10),
Padding = new MarginPadding(25), Padding = new MarginPadding(25),
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
@ -235,6 +235,7 @@ namespace osu.Game.Tournament.Screens.MapPool
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Height = 42,
}); });
} }
} }

View File

@ -62,7 +62,7 @@ namespace osu.Game.Tournament.Screens.Schedule
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
new DrawableTournamentTitleText(), new DrawableTournamentHeaderText(),
new Container new Container
{ {
Margin = new MarginPadding { Top = 40 }, Margin = new MarginPadding { Top = 40 },

View File

@ -15,7 +15,6 @@ using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models; using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.Ladder.Components; using osu.Game.Tournament.Screens.Ladder.Components;
using osuTK; using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tournament.Screens.TeamIntro namespace osu.Game.Tournament.Screens.TeamIntro
{ {
@ -140,9 +139,9 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Spacing = new Vector2(5), Spacing = new Vector2(5),
Children = new Drawable[] Children = new Drawable[]
{ {
new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = Color4.Black, }, new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = TournamentGame.TEXT_COLOUR, },
new TournamentSpriteText { Text = "by", Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, new TournamentSpriteText { Text = "by", Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
} }
}, },
new FillFlowContainer new FillFlowContainer
@ -154,8 +153,8 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Spacing = new Vector2(40), Spacing = new Vector2(40),
Children = new Drawable[] Children = new Drawable[]
{ {
new TournamentSpriteText { Text = beatmap.Score.ToString("#,0"), Colour = Color4.Black, Width = 80 }, new TournamentSpriteText { Text = beatmap.Score.ToString("#,0"), Colour = TournamentGame.TEXT_COLOUR, Width = 80 },
new TournamentSpriteText { Text = "#" + beatmap.Seed.Value.ToString("#,0"), Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, new TournamentSpriteText { Text = "#" + beatmap.Seed.Value.ToString("#,0"), Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
} }
}, },
}; };
@ -204,7 +203,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Black, Colour = TournamentGame.TEXT_COLOUR,
}, },
new TournamentSpriteText new TournamentSpriteText
{ {
@ -260,20 +259,18 @@ namespace osu.Game.Tournament.Screens.TeamIntro
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
var colour = OsuColour.Gray(0.3f);
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new TournamentSpriteText new TournamentSpriteText
{ {
Text = left, Text = left,
Colour = colour, Colour = TournamentGame.TEXT_COLOUR,
Font = OsuFont.Torus.With(size: 22), Font = OsuFont.Torus.With(size: 22, weight: FontWeight.SemiBold),
}, },
new TournamentSpriteText new TournamentSpriteText
{ {
Text = right, Text = right,
Colour = colour, Colour = TournamentGame.TEXT_COLOUR,
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopLeft, Origin = Anchor.TopLeft,
Font = OsuFont.Torus.With(size: 22, weight: FontWeight.Regular), Font = OsuFont.Torus.With(size: 22, weight: FontWeight.Regular),
@ -305,7 +302,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
{ {
Text = team?.FullName.Value ?? "???", Text = team?.FullName.Value ?? "???",
Font = OsuFont.Torus.With(size: 32, weight: FontWeight.SemiBold), Font = OsuFont.Torus.With(size: 32, weight: FontWeight.SemiBold),
Colour = Color4.Black, Colour = TournamentGame.TEXT_COLOUR,
}, },
} }
}; };

View File

@ -1,9 +1,9 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Game.Graphics;
using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Cursor;
using osu.Game.Tournament.Models; using osu.Game.Tournament.Models;
using osuTK.Graphics; using osuTK.Graphics;
@ -14,13 +14,13 @@ namespace osu.Game.Tournament
{ {
public static ColourInfo GetTeamColour(TeamColour teamColour) => teamColour == TeamColour.Red ? COLOUR_RED : COLOUR_BLUE; public static ColourInfo GetTeamColour(TeamColour teamColour) => teamColour == TeamColour.Red ? COLOUR_RED : COLOUR_BLUE;
public static readonly Color4 COLOUR_RED = OsuColour.FromHex("#AA1414"); public static readonly Color4 COLOUR_RED = Color4Extensions.FromHex("#AA1414");
public static readonly Color4 COLOUR_BLUE = OsuColour.FromHex("#1462AA"); public static readonly Color4 COLOUR_BLUE = Color4Extensions.FromHex("#1462AA");
public static readonly Color4 ELEMENT_BACKGROUND_COLOUR = OsuColour.FromHex("#fff"); public static readonly Color4 ELEMENT_BACKGROUND_COLOUR = Color4Extensions.FromHex("#fff");
public static readonly Color4 ELEMENT_FOREGROUND_COLOUR = OsuColour.FromHex("#000"); public static readonly Color4 ELEMENT_FOREGROUND_COLOUR = Color4Extensions.FromHex("#000");
public static readonly Color4 TEXT_COLOUR = OsuColour.FromHex("#fff"); public static readonly Color4 TEXT_COLOUR = Color4Extensions.FromHex("#fff");
protected override void LoadComplete() protected override void LoadComplete()
{ {

View File

@ -37,6 +37,8 @@ namespace osu.Game.Tournament
private Storage storage; private Storage storage;
private TournamentStorage tournamentStorage;
private DependencyContainer dependencies; private DependencyContainer dependencies;
private Bindable<Size> windowSize; private Bindable<Size> windowSize;
@ -54,7 +56,9 @@ namespace osu.Game.Tournament
{ {
Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly)); Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));
Textures.AddStore(new TextureLoaderStore(new ResourceStore<byte[]>(new StorageBackedResourceStore(storage)))); dependencies.CacheAs(tournamentStorage = new TournamentStorage(storage));
Textures.AddStore(new TextureLoaderStore(tournamentStorage));
this.storage = storage; this.storage = storage;

View File

@ -0,0 +1,19 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
namespace osu.Game.Tournament
{
internal class TournamentStorage : NamespacedResourceStore<byte[]>
{
public TournamentStorage(Storage storage)
: base(new StorageBackedResourceStore(storage), "tournament")
{
AddExtension("m4v");
AddExtension("avi");
AddExtension("mp4");
}
}
}

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -93,8 +92,8 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[1]); var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]); var origin = parseOrigin(split[2]);
var path = CleanFilename(split[3]); var path = CleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); var x = Parsing.ParseFloat(split[4], Parsing.MAX_COORDINATE_VALUE);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); var y = Parsing.ParseFloat(split[5], Parsing.MAX_COORDINATE_VALUE);
storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y));
storyboard.GetLayer(layer).Add(storyboardSprite); storyboard.GetLayer(layer).Add(storyboardSprite);
break; break;
@ -105,10 +104,10 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[1]); var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]); var origin = parseOrigin(split[2]);
var path = CleanFilename(split[3]); var path = CleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); var x = Parsing.ParseFloat(split[4], Parsing.MAX_COORDINATE_VALUE);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); var y = Parsing.ParseFloat(split[5], Parsing.MAX_COORDINATE_VALUE);
var frameCount = int.Parse(split[6]); var frameCount = Parsing.ParseInt(split[6]);
var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); var frameDelay = Parsing.ParseDouble(split[7]);
var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever;
storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType);
storyboard.GetLayer(layer).Add(storyboardSprite); storyboard.GetLayer(layer).Add(storyboardSprite);
@ -117,10 +116,10 @@ namespace osu.Game.Beatmaps.Formats
case LegacyEventType.Sample: case LegacyEventType.Sample:
{ {
var time = double.Parse(split[1], CultureInfo.InvariantCulture); var time = Parsing.ParseDouble(split[1]);
var layer = parseLayer(split[2]); var layer = parseLayer(split[2]);
var path = CleanFilename(split[3]); var path = CleanFilename(split[3]);
var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; var volume = split.Length > 4 ? Parsing.ParseFloat(split[4]) : 100;
storyboard.GetLayer(layer).Add(new StoryboardSampleInfo(path, time, (int)volume)); storyboard.GetLayer(layer).Add(new StoryboardSampleInfo(path, time, (int)volume));
break; break;
} }
@ -138,17 +137,17 @@ namespace osu.Game.Beatmaps.Formats
case "T": case "T":
{ {
var triggerName = split[1]; var triggerName = split[1];
var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue; var startTime = split.Length > 2 ? Parsing.ParseDouble(split[2]) : double.MinValue;
var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue; var endTime = split.Length > 3 ? Parsing.ParseDouble(split[3]) : double.MaxValue;
var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0; var groupNumber = split.Length > 4 ? Parsing.ParseInt(split[4]) : 0;
timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber); timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber);
break; break;
} }
case "L": case "L":
{ {
var startTime = double.Parse(split[1], CultureInfo.InvariantCulture); var startTime = Parsing.ParseDouble(split[1]);
var loopCount = int.Parse(split[2]); var loopCount = Parsing.ParseInt(split[2]);
timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount); timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount);
break; break;
} }
@ -158,52 +157,52 @@ namespace osu.Game.Beatmaps.Formats
if (string.IsNullOrEmpty(split[3])) if (string.IsNullOrEmpty(split[3]))
split[3] = split[2]; split[3] = split[2];
var easing = (Easing)int.Parse(split[1]); var easing = (Easing)Parsing.ParseInt(split[1]);
var startTime = double.Parse(split[2], CultureInfo.InvariantCulture); var startTime = Parsing.ParseDouble(split[2]);
var endTime = double.Parse(split[3], CultureInfo.InvariantCulture); var endTime = Parsing.ParseDouble(split[3]);
switch (commandType) switch (commandType)
{ {
case "F": case "F":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "S": case "S":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Scale.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.Scale.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "V": case "V":
{ {
var startX = float.Parse(split[4], CultureInfo.InvariantCulture); var startX = Parsing.ParseFloat(split[4]);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture); var startY = Parsing.ParseFloat(split[5]);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; var endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; var endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
timelineGroup?.VectorScale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); timelineGroup?.VectorScale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY));
break; break;
} }
case "R": case "R":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Rotation.Add(easing, startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue)); timelineGroup?.Rotation.Add(easing, startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue));
break; break;
} }
case "M": case "M":
{ {
var startX = float.Parse(split[4], CultureInfo.InvariantCulture); var startX = Parsing.ParseFloat(split[4]);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture); var startY = Parsing.ParseFloat(split[5]);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; var endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; var endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); timelineGroup?.X.Add(easing, startTime, endTime, startX, endX);
timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY);
break; break;
@ -211,28 +210,28 @@ namespace osu.Game.Beatmaps.Formats
case "MX": case "MX":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "MY": case "MY":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "C": case "C":
{ {
var startRed = float.Parse(split[4], CultureInfo.InvariantCulture); var startRed = Parsing.ParseFloat(split[4]);
var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture); var startGreen = Parsing.ParseFloat(split[5]);
var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture); var startBlue = Parsing.ParseFloat(split[6]);
var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed; var endRed = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startRed;
var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen; var endGreen = split.Length > 8 ? Parsing.ParseFloat(split[8]) : startGreen;
var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue; var endBlue = split.Length > 9 ? Parsing.ParseFloat(split[9]) : startBlue;
timelineGroup?.Colour.Add(easing, startTime, endTime, timelineGroup?.Colour.Add(easing, startTime, endTime,
new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1),
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1));

View File

@ -15,11 +15,13 @@ namespace osu.Game.Database
{ {
/// <summary> /// <summary>
/// Fired when a <typeparamref name="TModel"/> download begins. /// Fired when a <typeparamref name="TModel"/> download begins.
/// This is NOT run on the update thread and should be scheduled.
/// </summary> /// </summary>
event Action<ArchiveDownloadRequest<TModel>> DownloadBegan; event Action<ArchiveDownloadRequest<TModel>> DownloadBegan;
/// <summary> /// <summary>
/// Fired when a <typeparamref name="TModel"/> download is interrupted, either due to user cancellation or failure. /// Fired when a <typeparamref name="TModel"/> download is interrupted, either due to user cancellation or failure.
/// This is NOT run on the update thread and should be scheduled.
/// </summary> /// </summary>
event Action<ArchiveDownloadRequest<TModel>> DownloadFailed; event Action<ArchiveDownloadRequest<TModel>> DownloadFailed;

View File

@ -1,8 +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.Framework.Extensions.Color4Extensions;
using System.Globalization;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osuTK.Graphics; using osuTK.Graphics;
@ -13,45 +12,6 @@ namespace osu.Game.Graphics
public static Color4 Gray(float amt) => new Color4(amt, amt, amt, 1f); public static Color4 Gray(float amt) => new Color4(amt, amt, amt, 1f);
public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255); public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255);
public static Color4 FromHex(string hex)
{
var hexSpan = hex[0] == '#' ? hex.AsSpan().Slice(1) : hex.AsSpan();
switch (hexSpan.Length)
{
default:
throw new ArgumentException(@"Invalid hex string length!");
case 3:
return new Color4(
(byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17),
(byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17),
(byte)(byte.Parse(hexSpan.Slice(2, 1), NumberStyles.HexNumber) * 17),
255);
case 6:
return new Color4(
byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber),
byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber),
byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber),
255);
case 4:
return new Color4(
(byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17),
(byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17),
(byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17),
(byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17));
case 8:
return new Color4(
byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber),
byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber),
byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber),
byte.Parse(hexSpan.Slice(6, 2), NumberStyles.HexNumber));
}
}
public Color4 ForDifficultyRating(DifficultyRating difficulty, bool useLighterColour = false) public Color4 ForDifficultyRating(DifficultyRating difficulty, bool useLighterColour = false)
{ {
switch (difficulty) switch (difficulty)
@ -78,105 +38,105 @@ namespace osu.Game.Graphics
} }
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less // See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = FromHex(@"eeeeff"); public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff");
public readonly Color4 PurpleLight = FromHex(@"aa88ff"); public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff");
public readonly Color4 PurpleLightAlternative = FromHex(@"cba4da"); public readonly Color4 PurpleLightAlternative = Color4Extensions.FromHex(@"cba4da");
public readonly Color4 Purple = FromHex(@"8866ee"); public readonly Color4 Purple = Color4Extensions.FromHex(@"8866ee");
public readonly Color4 PurpleDark = FromHex(@"6644cc"); public readonly Color4 PurpleDark = Color4Extensions.FromHex(@"6644cc");
public readonly Color4 PurpleDarkAlternative = FromHex(@"312436"); public readonly Color4 PurpleDarkAlternative = Color4Extensions.FromHex(@"312436");
public readonly Color4 PurpleDarker = FromHex(@"441188"); public readonly Color4 PurpleDarker = Color4Extensions.FromHex(@"441188");
public readonly Color4 PinkLighter = FromHex(@"ffddee"); public readonly Color4 PinkLighter = Color4Extensions.FromHex(@"ffddee");
public readonly Color4 PinkLight = FromHex(@"ff99cc"); public readonly Color4 PinkLight = Color4Extensions.FromHex(@"ff99cc");
public readonly Color4 Pink = FromHex(@"ff66aa"); public readonly Color4 Pink = Color4Extensions.FromHex(@"ff66aa");
public readonly Color4 PinkDark = FromHex(@"cc5288"); public readonly Color4 PinkDark = Color4Extensions.FromHex(@"cc5288");
public readonly Color4 PinkDarker = FromHex(@"bb1177"); public readonly Color4 PinkDarker = Color4Extensions.FromHex(@"bb1177");
public readonly Color4 BlueLighter = FromHex(@"ddffff"); public readonly Color4 BlueLighter = Color4Extensions.FromHex(@"ddffff");
public readonly Color4 BlueLight = FromHex(@"99eeff"); public readonly Color4 BlueLight = Color4Extensions.FromHex(@"99eeff");
public readonly Color4 Blue = FromHex(@"66ccff"); public readonly Color4 Blue = Color4Extensions.FromHex(@"66ccff");
public readonly Color4 BlueDark = FromHex(@"44aadd"); public readonly Color4 BlueDark = Color4Extensions.FromHex(@"44aadd");
public readonly Color4 BlueDarker = FromHex(@"2299bb"); public readonly Color4 BlueDarker = Color4Extensions.FromHex(@"2299bb");
public readonly Color4 YellowLighter = FromHex(@"ffffdd"); public readonly Color4 YellowLighter = Color4Extensions.FromHex(@"ffffdd");
public readonly Color4 YellowLight = FromHex(@"ffdd55"); public readonly Color4 YellowLight = Color4Extensions.FromHex(@"ffdd55");
public readonly Color4 Yellow = FromHex(@"ffcc22"); public readonly Color4 Yellow = Color4Extensions.FromHex(@"ffcc22");
public readonly Color4 YellowDark = FromHex(@"eeaa00"); public readonly Color4 YellowDark = Color4Extensions.FromHex(@"eeaa00");
public readonly Color4 YellowDarker = FromHex(@"cc6600"); public readonly Color4 YellowDarker = Color4Extensions.FromHex(@"cc6600");
public readonly Color4 GreenLighter = FromHex(@"eeffcc"); public readonly Color4 GreenLighter = Color4Extensions.FromHex(@"eeffcc");
public readonly Color4 GreenLight = FromHex(@"b3d944"); public readonly Color4 GreenLight = Color4Extensions.FromHex(@"b3d944");
public readonly Color4 Green = FromHex(@"88b300"); public readonly Color4 Green = Color4Extensions.FromHex(@"88b300");
public readonly Color4 GreenDark = FromHex(@"668800"); public readonly Color4 GreenDark = Color4Extensions.FromHex(@"668800");
public readonly Color4 GreenDarker = FromHex(@"445500"); public readonly Color4 GreenDarker = Color4Extensions.FromHex(@"445500");
public readonly Color4 Sky = FromHex(@"6bb5ff"); public readonly Color4 Sky = Color4Extensions.FromHex(@"6bb5ff");
public readonly Color4 GreySkyLighter = FromHex(@"c6e3f4"); public readonly Color4 GreySkyLighter = Color4Extensions.FromHex(@"c6e3f4");
public readonly Color4 GreySkyLight = FromHex(@"8ab3cc"); public readonly Color4 GreySkyLight = Color4Extensions.FromHex(@"8ab3cc");
public readonly Color4 GreySky = FromHex(@"405461"); public readonly Color4 GreySky = Color4Extensions.FromHex(@"405461");
public readonly Color4 GreySkyDark = FromHex(@"303d47"); public readonly Color4 GreySkyDark = Color4Extensions.FromHex(@"303d47");
public readonly Color4 GreySkyDarker = FromHex(@"21272c"); public readonly Color4 GreySkyDarker = Color4Extensions.FromHex(@"21272c");
public readonly Color4 Seafoam = FromHex(@"05ffa2"); public readonly Color4 Seafoam = Color4Extensions.FromHex(@"05ffa2");
public readonly Color4 GreySeafoamLighter = FromHex(@"9ebab1"); public readonly Color4 GreySeafoamLighter = Color4Extensions.FromHex(@"9ebab1");
public readonly Color4 GreySeafoamLight = FromHex(@"4d7365"); public readonly Color4 GreySeafoamLight = Color4Extensions.FromHex(@"4d7365");
public readonly Color4 GreySeafoam = FromHex(@"33413c"); public readonly Color4 GreySeafoam = Color4Extensions.FromHex(@"33413c");
public readonly Color4 GreySeafoamDark = FromHex(@"2c3532"); public readonly Color4 GreySeafoamDark = Color4Extensions.FromHex(@"2c3532");
public readonly Color4 GreySeafoamDarker = FromHex(@"1e2422"); public readonly Color4 GreySeafoamDarker = Color4Extensions.FromHex(@"1e2422");
public readonly Color4 Cyan = FromHex(@"05f4fd"); public readonly Color4 Cyan = Color4Extensions.FromHex(@"05f4fd");
public readonly Color4 GreyCyanLighter = FromHex(@"77b1b3"); public readonly Color4 GreyCyanLighter = Color4Extensions.FromHex(@"77b1b3");
public readonly Color4 GreyCyanLight = FromHex(@"436d6f"); public readonly Color4 GreyCyanLight = Color4Extensions.FromHex(@"436d6f");
public readonly Color4 GreyCyan = FromHex(@"293d3e"); public readonly Color4 GreyCyan = Color4Extensions.FromHex(@"293d3e");
public readonly Color4 GreyCyanDark = FromHex(@"243536"); public readonly Color4 GreyCyanDark = Color4Extensions.FromHex(@"243536");
public readonly Color4 GreyCyanDarker = FromHex(@"1e2929"); public readonly Color4 GreyCyanDarker = Color4Extensions.FromHex(@"1e2929");
public readonly Color4 Lime = FromHex(@"82ff05"); public readonly Color4 Lime = Color4Extensions.FromHex(@"82ff05");
public readonly Color4 GreyLimeLighter = FromHex(@"deff87"); public readonly Color4 GreyLimeLighter = Color4Extensions.FromHex(@"deff87");
public readonly Color4 GreyLimeLight = FromHex(@"657259"); public readonly Color4 GreyLimeLight = Color4Extensions.FromHex(@"657259");
public readonly Color4 GreyLime = FromHex(@"3f443a"); public readonly Color4 GreyLime = Color4Extensions.FromHex(@"3f443a");
public readonly Color4 GreyLimeDark = FromHex(@"32352e"); public readonly Color4 GreyLimeDark = Color4Extensions.FromHex(@"32352e");
public readonly Color4 GreyLimeDarker = FromHex(@"2e302b"); public readonly Color4 GreyLimeDarker = Color4Extensions.FromHex(@"2e302b");
public readonly Color4 Violet = FromHex(@"bf04ff"); public readonly Color4 Violet = Color4Extensions.FromHex(@"bf04ff");
public readonly Color4 GreyVioletLighter = FromHex(@"ebb8fe"); public readonly Color4 GreyVioletLighter = Color4Extensions.FromHex(@"ebb8fe");
public readonly Color4 GreyVioletLight = FromHex(@"685370"); public readonly Color4 GreyVioletLight = Color4Extensions.FromHex(@"685370");
public readonly Color4 GreyViolet = FromHex(@"46334d"); public readonly Color4 GreyViolet = Color4Extensions.FromHex(@"46334d");
public readonly Color4 GreyVioletDark = FromHex(@"2c2230"); public readonly Color4 GreyVioletDark = Color4Extensions.FromHex(@"2c2230");
public readonly Color4 GreyVioletDarker = FromHex(@"201823"); public readonly Color4 GreyVioletDarker = Color4Extensions.FromHex(@"201823");
public readonly Color4 Carmine = FromHex(@"ff0542"); public readonly Color4 Carmine = Color4Extensions.FromHex(@"ff0542");
public readonly Color4 GreyCarmineLighter = FromHex(@"deaab4"); public readonly Color4 GreyCarmineLighter = Color4Extensions.FromHex(@"deaab4");
public readonly Color4 GreyCarmineLight = FromHex(@"644f53"); public readonly Color4 GreyCarmineLight = Color4Extensions.FromHex(@"644f53");
public readonly Color4 GreyCarmine = FromHex(@"342b2d"); public readonly Color4 GreyCarmine = Color4Extensions.FromHex(@"342b2d");
public readonly Color4 GreyCarmineDark = FromHex(@"302a2b"); public readonly Color4 GreyCarmineDark = Color4Extensions.FromHex(@"302a2b");
public readonly Color4 GreyCarmineDarker = FromHex(@"241d1e"); public readonly Color4 GreyCarmineDarker = Color4Extensions.FromHex(@"241d1e");
public readonly Color4 Gray0 = FromHex(@"000"); public readonly Color4 Gray0 = Color4Extensions.FromHex(@"000");
public readonly Color4 Gray1 = FromHex(@"111"); public readonly Color4 Gray1 = Color4Extensions.FromHex(@"111");
public readonly Color4 Gray2 = FromHex(@"222"); public readonly Color4 Gray2 = Color4Extensions.FromHex(@"222");
public readonly Color4 Gray3 = FromHex(@"333"); public readonly Color4 Gray3 = Color4Extensions.FromHex(@"333");
public readonly Color4 Gray4 = FromHex(@"444"); public readonly Color4 Gray4 = Color4Extensions.FromHex(@"444");
public readonly Color4 Gray5 = FromHex(@"555"); public readonly Color4 Gray5 = Color4Extensions.FromHex(@"555");
public readonly Color4 Gray6 = FromHex(@"666"); public readonly Color4 Gray6 = Color4Extensions.FromHex(@"666");
public readonly Color4 Gray7 = FromHex(@"777"); public readonly Color4 Gray7 = Color4Extensions.FromHex(@"777");
public readonly Color4 Gray8 = FromHex(@"888"); public readonly Color4 Gray8 = Color4Extensions.FromHex(@"888");
public readonly Color4 Gray9 = FromHex(@"999"); public readonly Color4 Gray9 = Color4Extensions.FromHex(@"999");
public readonly Color4 GrayA = FromHex(@"aaa"); public readonly Color4 GrayA = Color4Extensions.FromHex(@"aaa");
public readonly Color4 GrayB = FromHex(@"bbb"); public readonly Color4 GrayB = Color4Extensions.FromHex(@"bbb");
public readonly Color4 GrayC = FromHex(@"ccc"); public readonly Color4 GrayC = Color4Extensions.FromHex(@"ccc");
public readonly Color4 GrayD = FromHex(@"ddd"); public readonly Color4 GrayD = Color4Extensions.FromHex(@"ddd");
public readonly Color4 GrayE = FromHex(@"eee"); public readonly Color4 GrayE = Color4Extensions.FromHex(@"eee");
public readonly Color4 GrayF = FromHex(@"fff"); public readonly Color4 GrayF = Color4Extensions.FromHex(@"fff");
public readonly Color4 RedLighter = FromHex(@"ffeded"); public readonly Color4 RedLighter = Color4Extensions.FromHex(@"ffeded");
public readonly Color4 RedLight = FromHex(@"ed7787"); public readonly Color4 RedLight = Color4Extensions.FromHex(@"ed7787");
public readonly Color4 Red = FromHex(@"ed1121"); public readonly Color4 Red = Color4Extensions.FromHex(@"ed1121");
public readonly Color4 RedDark = FromHex(@"ba0011"); public readonly Color4 RedDark = Color4Extensions.FromHex(@"ba0011");
public readonly Color4 RedDarker = FromHex(@"870000"); public readonly Color4 RedDarker = Color4Extensions.FromHex(@"870000");
public readonly Color4 ChatBlue = FromHex(@"17292e"); public readonly Color4 ChatBlue = Color4Extensions.FromHex(@"17292e");
public readonly Color4 ContextMenuGray = FromHex(@"223034"); public readonly Color4 ContextMenuGray = Color4Extensions.FromHex(@"223034");
} }
} }

View File

@ -4,6 +4,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
@ -38,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface
sampleClick = audio.Samples.Get(@"UI/generic-select"); sampleClick = audio.Samples.Get(@"UI/generic-select");
BackgroundColour = Color4.Transparent; BackgroundColour = Color4.Transparent;
BackgroundColourHover = OsuColour.FromHex(@"172023"); BackgroundColourHover = Color4Extensions.FromHex(@"172023");
updateTextColour(); updateTextColour();
} }
@ -57,7 +58,7 @@ namespace osu.Game.Graphics.UserInterface
break; break;
case MenuItemType.Highlighted: case MenuItemType.Highlighted:
text.Colour = OsuColour.FromHex(@"ffcc22"); text.Colour = Color4Extensions.FromHex(@"ffcc22");
break; break;
} }
} }

View File

@ -2,6 +2,7 @@
// 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.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -42,7 +43,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("1c2125"), Colour = Color4Extensions.FromHex("1c2125"),
}, },
new FillFlowContainer new FillFlowContainer
{ {

View File

@ -53,17 +53,17 @@ namespace osu.Game.Online
manager.ItemRemoved += itemRemoved; manager.ItemRemoved += itemRemoved;
} }
private void downloadBegan(ArchiveDownloadRequest<TModel> request) private void downloadBegan(ArchiveDownloadRequest<TModel> request) => Schedule(() =>
{ {
if (request.Model.Equals(Model.Value)) if (request.Model.Equals(Model.Value))
attachDownload(request); attachDownload(request);
} });
private void downloadFailed(ArchiveDownloadRequest<TModel> request) private void downloadFailed(ArchiveDownloadRequest<TModel> request) => Schedule(() =>
{ {
if (request.Model.Equals(Model.Value)) if (request.Model.Equals(Model.Value))
attachDownload(null); attachDownload(null);
} });
private ArchiveDownloadRequest<TModel> attachedRequest; private ArchiveDownloadRequest<TModel> attachedRequest;

View File

@ -80,23 +80,23 @@ namespace osu.Game.Online.Leaderboards
{ {
case ScoreRank.XH: case ScoreRank.XH:
case ScoreRank.X: case ScoreRank.X:
return OsuColour.FromHex(@"ce1c9d"); return Color4Extensions.FromHex(@"ce1c9d");
case ScoreRank.SH: case ScoreRank.SH:
case ScoreRank.S: case ScoreRank.S:
return OsuColour.FromHex(@"00a8b5"); return Color4Extensions.FromHex(@"00a8b5");
case ScoreRank.A: case ScoreRank.A:
return OsuColour.FromHex(@"7cce14"); return Color4Extensions.FromHex(@"7cce14");
case ScoreRank.B: case ScoreRank.B:
return OsuColour.FromHex(@"e3b130"); return Color4Extensions.FromHex(@"e3b130");
case ScoreRank.C: case ScoreRank.C:
return OsuColour.FromHex(@"f18252"); return Color4Extensions.FromHex(@"f18252");
default: default:
return OsuColour.FromHex(@"e95353"); return Color4Extensions.FromHex(@"e95353");
} }
} }
@ -109,23 +109,23 @@ namespace osu.Game.Online.Leaderboards
{ {
case ScoreRank.XH: case ScoreRank.XH:
case ScoreRank.SH: case ScoreRank.SH:
return ColourInfo.GradientVertical(Color4.White, OsuColour.FromHex("afdff0")); return ColourInfo.GradientVertical(Color4.White, Color4Extensions.FromHex("afdff0"));
case ScoreRank.X: case ScoreRank.X:
case ScoreRank.S: case ScoreRank.S:
return ColourInfo.GradientVertical(OsuColour.FromHex(@"ffe7a8"), OsuColour.FromHex(@"ffb800")); return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"ffe7a8"), Color4Extensions.FromHex(@"ffb800"));
case ScoreRank.A: case ScoreRank.A:
return OsuColour.FromHex(@"275227"); return Color4Extensions.FromHex(@"275227");
case ScoreRank.B: case ScoreRank.B:
return OsuColour.FromHex(@"553a2b"); return Color4Extensions.FromHex(@"553a2b");
case ScoreRank.C: case ScoreRank.C:
return OsuColour.FromHex(@"473625"); return Color4Extensions.FromHex(@"473625");
default: default:
return OsuColour.FromHex(@"512525"); return Color4Extensions.FromHex(@"512525");
} }
} }
} }

View File

@ -200,7 +200,7 @@ namespace osu.Game.Online.Leaderboards
scoreLabel = new GlowingSpriteText scoreLabel = new GlowingSpriteText
{ {
TextColour = Color4.White, TextColour = Color4.White,
GlowColour = OsuColour.FromHex(@"83ccfa"), GlowColour = Color4Extensions.FromHex(@"83ccfa"),
Text = score.TotalScore.ToString(@"N0"), Text = score.TotalScore.ToString(@"N0"),
Font = OsuFont.Numeric.With(size: 23), Font = OsuFont.Numeric.With(size: 23),
}, },
@ -325,7 +325,7 @@ namespace osu.Game.Online.Leaderboards
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(icon_size), Size = new Vector2(icon_size),
Rotation = 45, Rotation = 45,
Colour = OsuColour.FromHex(@"3087ac"), Colour = Color4Extensions.FromHex(@"3087ac"),
Icon = FontAwesome.Solid.Square, Icon = FontAwesome.Solid.Square,
Shadow = true, Shadow = true,
}, },
@ -334,7 +334,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(icon_size - 6), Size = new Vector2(icon_size - 6),
Colour = OsuColour.FromHex(@"a4edff"), Colour = Color4Extensions.FromHex(@"a4edff"),
Icon = statistic.Icon, Icon = statistic.Icon,
}, },
}, },
@ -344,7 +344,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
TextColour = Color4.White, TextColour = Color4.White,
GlowColour = OsuColour.FromHex(@"83ccfa"), GlowColour = Color4Extensions.FromHex(@"83ccfa"),
Text = statistic.Value, Text = statistic.Value,
Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold), Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold),
}, },

View File

@ -3,6 +3,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
@ -124,7 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet
Icon = FontAwesome.Solid.Square, Icon = FontAwesome.Solid.Square,
Size = new Vector2(12), Size = new Vector2(12),
Rotation = 45, Rotation = 45,
Colour = OsuColour.FromHex(@"441288"), Colour = Color4Extensions.FromHex(@"441288"),
}, },
new SpriteIcon new SpriteIcon
{ {
@ -132,7 +133,7 @@ namespace osu.Game.Overlays.BeatmapSet
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = icon, Icon = icon,
Size = new Vector2(12), Size = new Vector2(12),
Colour = OsuColour.FromHex(@"f7dd55"), Colour = Color4Extensions.FromHex(@"f7dd55"),
Scale = new Vector2(0.8f), Scale = new Vector2(0.8f),
}, },
value = new OsuSpriteText value = new OsuSpriteText

View File

@ -2,8 +2,8 @@
// 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.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.BeatmapSet.Buttons namespace osu.Game.Overlays.BeatmapSet.Buttons
@ -19,9 +19,9 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
BackgroundColour = OsuColour.FromHex(@"094c5f"); BackgroundColour = Color4Extensions.FromHex(@"094c5f");
Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); Triangles.ColourLight = Color4Extensions.FromHex(@"0f7c9b");
Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); Triangles.ColourDark = Color4Extensions.FromHex(@"094c5f");
Triangles.TriangleScale = 1.5f; Triangles.TriangleScale = 1.5f;
} }
} }

View File

@ -52,22 +52,28 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
highAccuracyColour = colours.GreenLight; highAccuracyColour = colours.GreenLight;
} }
public IReadOnlyList<ScoreInfo> Scores private bool showPerformancePoints;
public void DisplayScores(IReadOnlyList<ScoreInfo> scores, bool showPerformanceColumn)
{ {
set ClearScores();
{
Content = null;
backgroundFlow.Clear();
if (value?.Any() != true) if (!scores.Any())
return; return;
for (int i = 0; i < value.Count; i++) showPerformancePoints = showPerformanceColumn;
backgroundFlow.Add(new ScoreTableRowBackground(i, value[i], row_height));
Columns = createHeaders(value[0]); for (int i = 0; i < scores.Count; i++)
Content = value.Select((s, i) => createContent(i, s)).ToArray().ToRectangular(); backgroundFlow.Add(new ScoreTableRowBackground(i, scores[i], row_height));
}
Columns = createHeaders(scores.FirstOrDefault());
Content = scores.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
}
public void ClearScores()
{
Content = null;
backgroundFlow.Clear();
} }
private TableColumn[] createHeaders(ScoreInfo score) private TableColumn[] createHeaders(ScoreInfo score)
@ -88,11 +94,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
columns.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95))); columns.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
columns.AddRange(new[] if (showPerformancePoints)
{ columns.Add(new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)));
new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)),
new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), columns.Add(new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)));
});
return columns.ToArray(); return columns.ToArray();
} }
@ -150,24 +155,25 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
}); });
} }
content.AddRange(new Drawable[] if (showPerformancePoints)
{ {
new OsuSpriteText content.Add(new OsuSpriteText
{ {
Text = $@"{score.PP:N0}", Text = $@"{score.PP:N0}",
Font = OsuFont.GetFont(size: text_size) Font = OsuFont.GetFont(size: text_size)
}, });
new FillFlowContainer }
content.Add(new FillFlowContainer
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(1),
ChildrenEnumerable = score.Mods.Select(m => new ModIcon(m)
{ {
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Spacing = new Vector2(1), Scale = new Vector2(0.3f)
ChildrenEnumerable = score.Mods.Select(m => new ModIcon(m) })
{
AutoSizeAxes = Axes.Both,
Scale = new Vector2(0.3f)
})
},
}); });
return content.ToArray(); return content.ToArray();

View File

@ -52,17 +52,17 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (value?.Scores.Any() != true) if (value?.Scores.Any() != true)
{ {
scoreTable.Scores = null; scoreTable.ClearScores();
scoreTable.Hide(); scoreTable.Hide();
return; return;
} }
var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList(); var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList();
var topScore = scoreInfos.First();
scoreTable.Scores = scoreInfos; scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked);
scoreTable.Show(); scoreTable.Show();
var topScore = scoreInfos.First();
var userScore = value.UserScore; var userScore = value.UserScore;
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -96,6 +97,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
totalScoreColumn.Text = $@"{value.TotalScore:N0}"; totalScoreColumn.Text = $@"{value.TotalScore:N0}";
accuracyColumn.Text = value.DisplayAccuracy; accuracyColumn.Text = value.DisplayAccuracy;
maxComboColumn.Text = $@"{value.MaxCombo:N0}x"; maxComboColumn.Text = $@"{value.MaxCombo:N0}x";
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.SortedStatistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value));

View File

@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Changelog
public Action ListingSelected; public Action ListingSelected;
public UpdateStreamBadgeArea Streams; public ChangelogUpdateStreamControl Streams;
private const string listing_string = "listing"; private const string listing_string = "listing";
@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Changelog
Horizontal = 65, Horizontal = 65,
Vertical = 20 Vertical = 20
}, },
Child = Streams = new UpdateStreamBadgeArea() Child = Streams = new ChangelogUpdateStreamControl()
} }
} }
}; };

View File

@ -0,0 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Overlays.Changelog
{
public class ChangelogUpdateStreamControl : OverlayStreamControl<APIUpdateStream>
{
protected override OverlayStreamItem<APIUpdateStream> CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value);
}
}

View File

@ -0,0 +1,28 @@
// 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 Humanizer;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osuTK.Graphics;
namespace osu.Game.Overlays.Changelog
{
public class ChangelogUpdateStreamItem : OverlayStreamItem<APIUpdateStream>
{
public ChangelogUpdateStreamItem(APIUpdateStream stream)
: base(stream)
{
if (stream.IsFeatured)
Width *= 2;
}
protected override string MainText => Value.DisplayName;
protected override string AdditionalText => Value.LatestBuild.DisplayVersion;
protected override string InfoText => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null;
protected override Color4 GetBarColour(OsuColour colours) => Value.Colour;
}
}

View File

@ -123,7 +123,7 @@ namespace osu.Game.Overlays.Chat
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Radius = 1, Radius = 1,
Colour = OsuColour.FromHex(message.Sender.Colour), Colour = Color4Extensions.FromHex(message.Sender.Colour),
Type = EdgeEffectType.Shadow, Type = EdgeEffectType.Shadow,
}, },
Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 }, Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 },
@ -172,7 +172,7 @@ namespace osu.Game.Overlays.Chat
t.Font = OsuFont.GetFont(italics: true); t.Font = OsuFont.GetFont(italics: true);
if (senderHasBackground) if (senderHasBackground)
t.Colour = OsuColour.FromHex(message.Sender.Colour); t.Colour = Color4Extensions.FromHex(message.Sender.Colour);
} }
t.Font = t.Font.With(size: TextSize); t.Font = t.Font.With(size: TextSize);
@ -249,41 +249,41 @@ namespace osu.Game.Overlays.Chat
private static readonly Color4[] username_colours = private static readonly Color4[] username_colours =
{ {
OsuColour.FromHex("588c7e"), Color4Extensions.FromHex("588c7e"),
OsuColour.FromHex("b2a367"), Color4Extensions.FromHex("b2a367"),
OsuColour.FromHex("c98f65"), Color4Extensions.FromHex("c98f65"),
OsuColour.FromHex("bc5151"), Color4Extensions.FromHex("bc5151"),
OsuColour.FromHex("5c8bd6"), Color4Extensions.FromHex("5c8bd6"),
OsuColour.FromHex("7f6ab7"), Color4Extensions.FromHex("7f6ab7"),
OsuColour.FromHex("a368ad"), Color4Extensions.FromHex("a368ad"),
OsuColour.FromHex("aa6880"), Color4Extensions.FromHex("aa6880"),
OsuColour.FromHex("6fad9b"), Color4Extensions.FromHex("6fad9b"),
OsuColour.FromHex("f2e394"), Color4Extensions.FromHex("f2e394"),
OsuColour.FromHex("f2ae72"), Color4Extensions.FromHex("f2ae72"),
OsuColour.FromHex("f98f8a"), Color4Extensions.FromHex("f98f8a"),
OsuColour.FromHex("7daef4"), Color4Extensions.FromHex("7daef4"),
OsuColour.FromHex("a691f2"), Color4Extensions.FromHex("a691f2"),
OsuColour.FromHex("c894d3"), Color4Extensions.FromHex("c894d3"),
OsuColour.FromHex("d895b0"), Color4Extensions.FromHex("d895b0"),
OsuColour.FromHex("53c4a1"), Color4Extensions.FromHex("53c4a1"),
OsuColour.FromHex("eace5c"), Color4Extensions.FromHex("eace5c"),
OsuColour.FromHex("ea8c47"), Color4Extensions.FromHex("ea8c47"),
OsuColour.FromHex("fc4f4f"), Color4Extensions.FromHex("fc4f4f"),
OsuColour.FromHex("3d94ea"), Color4Extensions.FromHex("3d94ea"),
OsuColour.FromHex("7760ea"), Color4Extensions.FromHex("7760ea"),
OsuColour.FromHex("af52c6"), Color4Extensions.FromHex("af52c6"),
OsuColour.FromHex("e25696"), Color4Extensions.FromHex("e25696"),
OsuColour.FromHex("677c66"), Color4Extensions.FromHex("677c66"),
OsuColour.FromHex("9b8732"), Color4Extensions.FromHex("9b8732"),
OsuColour.FromHex("8c5129"), Color4Extensions.FromHex("8c5129"),
OsuColour.FromHex("8c3030"), Color4Extensions.FromHex("8c3030"),
OsuColour.FromHex("1f5d91"), Color4Extensions.FromHex("1f5d91"),
OsuColour.FromHex("4335a5"), Color4Extensions.FromHex("4335a5"),
OsuColour.FromHex("812a96"), Color4Extensions.FromHex("812a96"),
OsuColour.FromHex("992861"), Color4Extensions.FromHex("992861"),
}; };
} }
} }

View File

@ -41,10 +41,10 @@ namespace osu.Game.Overlays.Chat.Selection
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Waves.FirstWaveColour = OsuColour.FromHex("353535"); Waves.FirstWaveColour = Color4Extensions.FromHex("353535");
Waves.SecondWaveColour = OsuColour.FromHex("434343"); Waves.SecondWaveColour = Color4Extensions.FromHex("434343");
Waves.ThirdWaveColour = OsuColour.FromHex("515151"); Waves.ThirdWaveColour = Color4Extensions.FromHex("515151");
Waves.FourthWaveColour = OsuColour.FromHex("595959"); Waves.FourthWaveColour = Color4Extensions.FromHex("595959");
Children = new Drawable[] Children = new Drawable[]
{ {
@ -154,7 +154,7 @@ namespace osu.Game.Overlays.Chat.Selection
{ {
bg.Colour = colours.Gray3; bg.Colour = colours.Gray3;
triangles.ColourDark = colours.Gray3; triangles.ColourDark = colours.Gray3;
triangles.ColourLight = OsuColour.FromHex(@"353535"); triangles.ColourLight = Color4Extensions.FromHex(@"353535");
headerBg.Colour = colours.Gray2.Opacity(0.75f); headerBg.Colour = colours.Gray2.Opacity(0.75f);
} }

View File

@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat.Tabs
{ {
var user = Value.Users.First(); var user = Value.Users.First();
BackgroundActive = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark; BackgroundActive = user.Colour != null ? Color4Extensions.FromHex(user.Colour) : colours.BlueDark;
BackgroundInactive = BackgroundActive.Darken(0.5f); BackgroundInactive = BackgroundActive.Darken(0.5f);
} }
} }

View File

@ -10,7 +10,6 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osuTK; using osuTK;
@ -114,13 +113,13 @@ namespace osu.Game.Overlays.Dialog
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"221a21"), Colour = Color4Extensions.FromHex(@"221a21"),
}, },
new Triangles new Triangles
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
ColourLight = OsuColour.FromHex(@"271e26"), ColourLight = Color4Extensions.FromHex(@"271e26"),
ColourDark = OsuColour.FromHex(@"1e171e"), ColourDark = Color4Extensions.FromHex(@"1e171e"),
TriangleScale = 4, TriangleScale = 4,
}, },
}, },

View File

@ -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.Game.Graphics; using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Dialog namespace osu.Game.Overlays.Dialog
@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Dialog
public PopupDialogButton() public PopupDialogButton()
{ {
Height = 50; Height = 50;
BackgroundColour = OsuColour.FromHex(@"150e14"); BackgroundColour = Color4Extensions.FromHex(@"150e14");
TextSize = 18; TextSize = 18;
} }
} }

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Direct
{ {
private DirectRulesetSelector rulesetSelector; private DirectRulesetSelector rulesetSelector;
protected override Color4 BackgroundColour => OsuColour.FromHex(@"384552"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"384552");
protected override DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked; protected override DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked;
protected override BeatmapSearchCategory DefaultCategory => BeatmapSearchCategory.Leaderboard; protected override BeatmapSearchCategory DefaultCategory => BeatmapSearchCategory.Leaderboard;

View File

@ -2,6 +2,7 @@
// 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 osu.Framework.Extensions.Color4Extensions;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Direct
{ {
public class Header : SearchableListHeader<DirectTab> public class Header : SearchableListHeader<DirectTab>
{ {
protected override Color4 BackgroundColour => OsuColour.FromHex(@"252f3a"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"252f3a");
protected override DirectTab DefaultTab => DirectTab.Search; protected override DirectTab DefaultTab => DirectTab.Search;
protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", Font = OsuFont.GetFont(size: 25) }; protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", Font = OsuFont.GetFont(size: 25) };

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Humanizer; using Humanizer;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Threading; using osu.Framework.Threading;
@ -34,9 +35,9 @@ namespace osu.Game.Overlays
private readonly OsuSpriteText resultCountsText; private readonly OsuSpriteText resultCountsText;
private FillFlowContainer<DirectPanel> panels; private FillFlowContainer<DirectPanel> panels;
protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"485e74");
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71"); protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"465b71");
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"3f5265"); protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"3f5265");
protected override SearchableListHeader<DirectTab> CreateHeader() => new Header(); protected override SearchableListHeader<DirectTab> CreateHeader() => new Header();
protected override SearchableListFilterControl<DirectSortCriteria, BeatmapSearchCategory> CreateFilterControl() => new FilterControl(); protected override SearchableListFilterControl<DirectSortCriteria, BeatmapSearchCategory> CreateFilterControl() => new FilterControl();

View File

@ -0,0 +1,25 @@
// 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.
namespace osu.Game.Overlays.Home.Friends
{
public class FriendsBundle
{
public FriendsOnlineStatus Status { get; }
public int Count { get; }
public FriendsBundle(FriendsOnlineStatus status, int count)
{
Status = status;
Count = count;
}
}
public enum FriendsOnlineStatus
{
All,
Online,
Offline
}
}

View File

@ -0,0 +1,26 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Game.Users;
namespace osu.Game.Overlays.Home.Friends
{
public class FriendsOnlineStatusControl : OverlayStreamControl<FriendsBundle>
{
protected override OverlayStreamItem<FriendsBundle> CreateStreamItem(FriendsBundle value) => new FriendsOnlineStatusItem(value);
public void Populate(List<User> users)
{
var userCount = users.Count;
var onlineUsersCount = users.Count(user => user.IsOnline);
AddItem(new FriendsBundle(FriendsOnlineStatus.All, userCount));
AddItem(new FriendsBundle(FriendsOnlineStatus.Online, onlineUsersCount));
AddItem(new FriendsBundle(FriendsOnlineStatus.Offline, userCount - onlineUsersCount));
Current.Value = Items.FirstOrDefault();
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Overlays.Home.Friends
{
public class FriendsOnlineStatusItem : OverlayStreamItem<FriendsBundle>
{
public FriendsOnlineStatusItem(FriendsBundle value)
: base(value)
{
}
protected override string MainText => Value.Status.ToString();
protected override string AdditionalText => Value.Count.ToString();
protected override Color4 GetBarColour(OsuColour colours)
{
switch (Value.Status)
{
case FriendsOnlineStatus.All:
return Color4.White;
case FriendsOnlineStatus.Online:
return colours.GreenLight;
case FriendsOnlineStatus.Offline:
return Color4.Black;
default:
throw new ArgumentException($@"{Value.Status} status does not provide a colour in {nameof(GetBarColour)}.");
}
}
}
}

View File

@ -126,14 +126,14 @@ namespace osu.Game.Overlays
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"05262f"), Colour = Color4Extensions.FromHex(@"05262f"),
}, },
new Triangles new Triangles
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
TriangleScale = 2, TriangleScale = 2,
ColourDark = OsuColour.FromHex(@"04222b"), ColourDark = Color4Extensions.FromHex(@"04222b"),
ColourLight = OsuColour.FromHex(@"052933"), ColourLight = Color4Extensions.FromHex(@"052933"),
}, },
innerSpin = new Sprite innerSpin = new Sprite
{ {

View File

@ -63,10 +63,10 @@ namespace osu.Game.Overlays.Mods
public ModSelectOverlay() public ModSelectOverlay()
{ {
Waves.FirstWaveColour = OsuColour.FromHex(@"19b0e2"); Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2");
Waves.SecondWaveColour = OsuColour.FromHex(@"2280a2"); Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2");
Waves.ThirdWaveColour = OsuColour.FromHex(@"005774"); Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774");
Waves.FourthWaveColour = OsuColour.FromHex(@"003a4e"); Waves.FourthWaveColour = Color4Extensions.FromHex(@"003a4e");
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;

View File

@ -3,42 +3,32 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Online.API.Requests.Responses;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using JetBrains.Annotations;
namespace osu.Game.Overlays.Changelog namespace osu.Game.Overlays
{ {
public class UpdateStreamBadgeArea : TabControl<APIUpdateStream> public abstract class OverlayStreamControl<T> : TabControl<T>
{ {
public UpdateStreamBadgeArea() protected OverlayStreamControl()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
} }
public void Populate(List<APIUpdateStream> streams) public void Populate(List<T> streams) => streams.ForEach(AddItem);
protected override Dropdown<T> CreateDropdown() => null;
protected override TabItem<T> CreateTabItem(T value) => CreateStreamItem(value).With(item =>
{ {
foreach (var updateStream in streams) item.SelectedItem.BindTo(Current);
AddItem(updateStream); });
}
protected override bool OnHover(HoverEvent e) [NotNull]
{ protected abstract OverlayStreamItem<T> CreateStreamItem(T value);
foreach (var streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
streamBadge.UserHoveringArea = true;
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
foreach (var streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
streamBadge.UserHoveringArea = false;
base.OnHoverLost(e);
}
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
{ {
@ -47,9 +37,20 @@ namespace osu.Game.Overlays.Changelog
AllowMultiline = true, AllowMultiline = true,
}; };
protected override Dropdown<APIUpdateStream> CreateDropdown() => null; protected override bool OnHover(HoverEvent e)
{
foreach (var streamBadge in TabContainer.Children.OfType<OverlayStreamItem<T>>())
streamBadge.UserHoveringArea = true;
protected override TabItem<APIUpdateStream> CreateTabItem(APIUpdateStream value) => return base.OnHover(e);
new UpdateStreamBadge(value) { SelectedTab = { BindTarget = Current } }; }
protected override void OnHoverLost(HoverLostEvent e)
{
foreach (var streamBadge in TabContainer.Children.OfType<OverlayStreamItem<T>>())
streamBadge.UserHoveringArea = false;
base.OnHoverLost(e);
}
} }
} }

View File

@ -1,46 +1,52 @@
// 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 Humanizer;
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.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites; using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osuTK; using osu.Framework.Graphics.Sprites;
using osu.Framework.Allocation;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Overlays.Changelog namespace osu.Game.Overlays
{ {
public class UpdateStreamBadge : TabItem<APIUpdateStream> public abstract class OverlayStreamItem<T> : TabItem<T>
{ {
private const float badge_width = 100; public readonly Bindable<T> SelectedItem = new Bindable<T>();
private const float transition_duration = 100;
public readonly Bindable<APIUpdateStream> SelectedTab = new Bindable<APIUpdateStream>(); private bool userHoveringArea;
private readonly APIUpdateStream stream; public bool UserHoveringArea
{
set
{
if (value == userHoveringArea)
return;
userHoveringArea = value;
updateState();
}
}
private FillFlowContainer<SpriteText> text; private FillFlowContainer<SpriteText> text;
private ExpandingBar expandingBar; private ExpandingBar expandingBar;
public UpdateStreamBadge(APIUpdateStream stream) protected OverlayStreamItem(T value)
: base(stream) : base(value)
{ {
this.stream = stream; Height = 60;
Width = 100;
Padding = new MarginPadding(5);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider) private void load(OverlayColourProvider colourProvider, OsuColour colours)
{ {
Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, 60);
Padding = new MarginPadding(5);
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
text = new FillFlowContainer<SpriteText> text = new FillFlowContainer<SpriteText>
@ -52,17 +58,17 @@ namespace osu.Game.Overlays.Changelog
{ {
new OsuSpriteText new OsuSpriteText
{ {
Text = stream.DisplayName, Text = MainText,
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black), Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black),
}, },
new OsuSpriteText new OsuSpriteText
{ {
Text = stream.LatestBuild.DisplayVersion, Text = AdditionalText,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
}, },
new OsuSpriteText new OsuSpriteText
{ {
Text = stream.LatestBuild.Users > 0 ? $"{"user".ToQuantity(stream.LatestBuild.Users, "N0")} online" : null, Text = InfoText,
Font = OsuFont.GetFont(size: 10), Font = OsuFont.GetFont(size: 10),
Colour = colourProvider.Foreground1 Colour = colourProvider.Foreground1
}, },
@ -71,7 +77,7 @@ namespace osu.Game.Overlays.Changelog
expandingBar = new ExpandingBar expandingBar = new ExpandingBar
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Colour = stream.Colour, Colour = GetBarColour(colours),
ExpandedSize = 4, ExpandedSize = 4,
CollapsedSize = 2, CollapsedSize = 2,
Expanded = true Expanded = true
@ -79,9 +85,17 @@ namespace osu.Game.Overlays.Changelog
new HoverClickSounds() new HoverClickSounds()
}); });
SelectedTab.BindValueChanged(_ => updateState(), true); SelectedItem.BindValueChanged(_ => updateState(), true);
} }
protected abstract string MainText { get; }
protected abstract string AdditionalText { get; }
protected virtual string InfoText => string.Empty;
protected abstract Color4 GetBarColour(OsuColour colours);
protected override void OnActivated() => updateState(); protected override void OnActivated() => updateState();
protected override void OnDeactivated() => updateState(); protected override void OnDeactivated() => updateState();
@ -104,7 +118,7 @@ namespace osu.Game.Overlays.Changelog
bool textHighlighted = IsHovered; bool textHighlighted = IsHovered;
bool barExpanded = IsHovered; bool barExpanded = IsHovered;
if (SelectedTab.Value == null) if (SelectedItem.Value == null)
{ {
// at listing, all badges are highlighted when user is not hovering any badge. // at listing, all badges are highlighted when user is not hovering any badge.
textHighlighted |= !userHoveringArea; textHighlighted |= !userHoveringArea;
@ -120,21 +134,7 @@ namespace osu.Game.Overlays.Changelog
} }
expandingBar.Expanded = barExpanded; expandingBar.Expanded = barExpanded;
text.FadeTo(textHighlighted ? 1 : 0.5f, transition_duration, Easing.OutQuint); text.FadeTo(textHighlighted ? 1 : 0.5f, 100, Easing.OutQuint);
}
private bool userHoveringArea;
public bool UserHoveringArea
{
set
{
if (value == userHoveringArea)
return;
userHoveringArea = value;
updateState();
}
} }
} }
} }

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -170,7 +171,7 @@ namespace osu.Game.Overlays.Profile.Header
userCountryText.Text = user?.Country?.FullName ?? "Alien"; userCountryText.Text = user?.Country?.FullName ?? "Alien";
supporterTag.SupportLevel = user?.SupportLevel ?? 0; supporterTag.SupportLevel = user?.SupportLevel ?? 0;
titleText.Text = user?.Title ?? string.Empty; titleText.Text = user?.Title ?? string.Empty;
titleText.Colour = OsuColour.FromHex(user?.Colour ?? "fff"); titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff");
userStats.Clear(); userStats.Clear();

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header;
using osu.Game.Users; using osu.Game.Users;
@ -48,7 +47,7 @@ namespace osu.Game.Overlays.Profile
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(OsuColour.FromHex("222").Opacity(0.8f), OsuColour.FromHex("222").Opacity(0.2f)) Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("222").Opacity(0.8f), Color4Extensions.FromHex("222").Opacity(0.2f))
}, },
} }
}; };

View File

@ -1,16 +1,16 @@
// 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.Extensions.Color4Extensions;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Overlays.SearchableList; using osu.Game.Overlays.SearchableList;
namespace osu.Game.Overlays.Social namespace osu.Game.Overlays.Social
{ {
public class FilterControl : SearchableListFilterControl<SocialSortCriteria, SortDirection> public class FilterControl : SearchableListFilterControl<SocialSortCriteria, SortDirection>
{ {
protected override Color4 BackgroundColour => OsuColour.FromHex(@"47253a"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"47253a");
protected override SocialSortCriteria DefaultTab => SocialSortCriteria.Rank; protected override SocialSortCriteria DefaultTab => SocialSortCriteria.Rank;
protected override SortDirection DefaultCategory => SortDirection.Ascending; protected override SortDirection DefaultCategory => SortDirection.Ascending;

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
namespace osu.Game.Overlays.Social namespace osu.Game.Overlays.Social
@ -17,7 +18,7 @@ namespace osu.Game.Overlays.Social
{ {
private OsuSpriteText browser; private OsuSpriteText browser;
protected override Color4 BackgroundColour => OsuColour.FromHex(@"38202e"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"38202e");
protected override SocialTab DefaultTab => SocialTab.AllPlayers; protected override SocialTab DefaultTab => SocialTab.AllPlayers;
protected override IconUsage Icon => FontAwesome.Solid.Users; protected override IconUsage Icon => FontAwesome.Solid.Users;

View File

@ -9,7 +9,6 @@ using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
@ -18,6 +17,7 @@ using osu.Game.Overlays.Social;
using osu.Game.Users; using osu.Game.Users;
using System.Threading; using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Threading; using osu.Framework.Threading;
namespace osu.Game.Overlays namespace osu.Game.Overlays
@ -27,9 +27,9 @@ namespace osu.Game.Overlays
private readonly LoadingSpinner loading; private readonly LoadingSpinner loading;
private FillFlowContainer<SocialPanel> panels; private FillFlowContainer<SocialPanel> panels;
protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"60284b");
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"672b51"); protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"672b51");
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"5c2648"); protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"5c2648");
protected override SearchableListHeader<SocialTab> CreateHeader() => new Header(); protected override SearchableListHeader<SocialTab> CreateHeader() => new Header();
protected override SearchableListFilterControl<SocialSortCriteria, SortDirection> CreateFilterControl() => new FilterControl(); protected override SearchableListFilterControl<SocialSortCriteria, SortDirection> CreateFilterControl() => new FilterControl();

View File

@ -14,22 +14,8 @@ namespace osu.Game.Overlays.Volume
public Func<GlobalAction, bool> ActionRequested; public Func<GlobalAction, bool> ActionRequested;
public Func<GlobalAction, float, bool, bool> ScrollActionRequested; public Func<GlobalAction, float, bool, bool> ScrollActionRequested;
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action) =>
{ ActionRequested?.Invoke(action) ?? false;
// if nothing else handles selection actions in the game, it's safe to let volume be adjusted.
switch (action)
{
case GlobalAction.SelectPrevious:
action = GlobalAction.IncreaseVolume;
break;
case GlobalAction.SelectNext:
action = GlobalAction.DecreaseVolume;
break;
}
return ActionRequested?.Invoke(action) ?? false;
}
public bool OnScroll(GlobalAction action, float amount, bool isPrecise) => public bool OnScroll(GlobalAction action, float amount, bool isPrecise) =>
ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false; ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false;

View File

@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => OsuIcon.ModPerfect; public override IconUsage? Icon => OsuIcon.ModPerfect;
public override string Description => "SS or quit."; public override string Description => "SS or quit.";
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => result.Type != result.Judgement.MaxResult; protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
=> !(result.Judgement is IgnoreJudgement)
&& result.Type != result.Judgement.MaxResult;
} }
} }

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -26,7 +27,7 @@ namespace osu.Game.Screens.Edit.Components.Menus
MaskingContainer.CornerRadius = 0; MaskingContainer.CornerRadius = 0;
ItemsContainer.Padding = new MarginPadding { Left = 100 }; ItemsContainer.Padding = new MarginPadding { Left = 100 };
BackgroundColour = OsuColour.FromHex("111"); BackgroundColour = Color4Extensions.FromHex("111");
ScreenSelectionTabControl tabControl; ScreenSelectionTabControl tabControl;
AddRangeInternal(new Drawable[] AddRangeInternal(new Drawable[]

View File

@ -2,11 +2,11 @@
// 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.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osuTK; using osuTK;
@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("111") Colour = Color4Extensions.FromHex("111")
}, },
new GridContainer new GridContainer
{ {
@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("222") Colour = Color4Extensions.FromHex("222")
}, },
new FillFlowContainer new FillFlowContainer
{ {
@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("333") Colour = Color4Extensions.FromHex("333")
}, },
new Container<TimelineButton> new Container<TimelineButton>
{ {

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Utils;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Online.API; using osu.Game.Online.API;
@ -33,6 +34,7 @@ namespace osu.Game.Screens.Menu
private readonly OsuScreen nextScreen; private readonly OsuScreen nextScreen;
private readonly Bindable<User> currentUser = new Bindable<User>(); private readonly Bindable<User> currentUser = new Bindable<User>();
private FillFlowContainer fill;
public Disclaimer(OsuScreen nextScreen = null) public Disclaimer(OsuScreen nextScreen = null)
{ {
@ -49,16 +51,16 @@ namespace osu.Game.Screens.Menu
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.Solid.ExclamationTriangle, Icon = FontAwesome.Solid.Poo,
Size = new Vector2(icon_size), Size = new Vector2(icon_size),
Y = icon_y, Y = icon_y,
}, },
new FillFlowContainer fill = new FillFlowContainer
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Y = icon_y + icon_size, Y = icon_y,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Children = new Drawable[] Children = new Drawable[]
@ -71,6 +73,8 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Spacing = new Vector2(0, 2), Spacing = new Vector2(0, 2),
LayoutDuration = 2000,
LayoutEasing = Easing.OutQuint
}, },
supportFlow = new LinkFlowContainer supportFlow = new LinkFlowContainer
{ {
@ -86,23 +90,16 @@ namespace osu.Game.Screens.Menu
} }
}; };
textFlow.AddText("This is an ", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.Light)); textFlow.AddText("This project is an ongoing ", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.Light));
textFlow.AddText("early development build", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.SemiBold)); textFlow.AddText("work in progress", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.SemiBold));
textFlow.AddParagraph("Things may not work as expected", t => t.Font = t.Font.With(size: 20));
textFlow.NewParagraph(); textFlow.NewParagraph();
static void format(SpriteText t) => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold); static void format(SpriteText t) => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold);
textFlow.AddParagraph("Detailed bug reports are welcomed via github issues.", format); textFlow.AddParagraph(getRandomTip(), t => t.Font = t.Font.With(Typeface.Exo, 20, FontWeight.SemiBold));
textFlow.NewParagraph(); textFlow.NewParagraph();
textFlow.AddText("Visit ", format);
textFlow.AddLink("discord.gg/ppy", "https://discord.gg/ppy", creationParameters: format);
textFlow.AddText(" to help out or follow progress!", format);
textFlow.NewParagraph();
textFlow.NewParagraph();
textFlow.NewParagraph(); textFlow.NewParagraph();
iconColour = colours.Yellow; iconColour = colours.Yellow;
@ -114,7 +111,7 @@ namespace osu.Game.Screens.Menu
if (e.NewValue.IsSupporter) if (e.NewValue.IsSupporter)
{ {
supportFlow.AddText("Thank you for supporting osu!", format); supportFlow.AddText("Eternal thanks to you for supporting osu!", format);
} }
else else
{ {
@ -125,7 +122,7 @@ namespace osu.Game.Screens.Menu
heart = supportFlow.AddIcon(FontAwesome.Solid.Heart, t => heart = supportFlow.AddIcon(FontAwesome.Solid.Heart, t =>
{ {
t.Padding = new MarginPadding { Left = 5 }; t.Padding = new MarginPadding { Left = 5, Top = 3 };
t.Font = t.Font.With(size: 12); t.Font = t.Font.With(size: 12);
t.Origin = Anchor.Centre; t.Origin = Anchor.Centre;
t.Colour = colours.Pink; t.Colour = colours.Pink;
@ -139,11 +136,6 @@ namespace osu.Game.Screens.Menu
}, true); }, true);
} }
private void animateHeart()
{
heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -155,15 +147,28 @@ namespace osu.Game.Screens.Menu
{ {
base.OnEntering(last); base.OnEntering(last);
icon.Delay(1000).FadeColour(iconColour, 200, Easing.OutQuint); icon.RotateTo(10);
icon.Delay(1000) icon.FadeOut();
.MoveToY(icon_y * 1.1f, 160, Easing.OutCirc) icon.ScaleTo(0.5f);
.RotateTo(-10, 160, Easing.OutCirc)
.Then() icon.Delay(500).FadeIn(500).ScaleTo(1, 500, Easing.OutQuint);
.MoveToY(icon_y, 160, Easing.InCirc)
.RotateTo(0, 160, Easing.InCirc); using (BeginDelayedSequence(3000, true))
{
icon.FadeColour(iconColour, 200, Easing.OutQuint);
icon.MoveToY(icon_y * 1.3f, 500, Easing.OutCirc)
.RotateTo(-360, 520, Easing.OutQuint)
.Then()
.MoveToY(icon_y, 160, Easing.InQuart)
.FadeColour(Color4.White, 160);
fill.Delay(520 + 160).MoveToOffset(new Vector2(0, 15), 160, Easing.OutQuart);
}
supportFlow.FadeOut().Delay(2000).FadeIn(500); supportFlow.FadeOut().Delay(2000).FadeIn(500);
double delay = 500;
foreach (var c in textFlow.Children)
c.FadeTo(0.001f).Delay(delay += 20).FadeIn(500);
animateHeart(); animateHeart();
@ -178,5 +183,35 @@ namespace osu.Game.Screens.Menu
this.Push(nextScreen); this.Push(nextScreen);
}); });
} }
private string getRandomTip()
{
string[] tips =
{
"You can press Ctrl-T anywhere in the game to toggle the toolbar!",
"You can press Ctrl-O anywhere in the game to access options!",
"All settings are dynamic and take effect in real-time. Try changing the skin while playing!",
"New features are coming online every update. Make sure to stay up-to-date!",
"If you find the UI too large or small, try adjusting UI scale in settings!",
"Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!",
"For now, osu!direct is available to all users on lazer. You can access it anywhere using Ctrl-D!",
"Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!",
"Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!",
"Try scrolling down in the mod select panel to find a bunch of new fun mods!",
"Most of the web content (profiles, rankings, etc.) are available natively in-game from the icons on the toolbar!",
"Get more details, hide or delete a beatmap by right-clicking on its panel at song select!",
"All delete operations are temporary until exiting. Restore accidentally deleted content from the maintenance settings!",
"Check out the \"timeshift\" multiplayer system, which has local permanent leaderboards and playlist support!",
"Toggle advanced frame / thread statistics with Ctrl-F11!",
"Take a look under the hood at performance counters and enable verbose performance logging with Ctrl-F2!",
};
return tips[RNG.Next(0, tips.Length)];
}
private void animateHeart()
{
heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
}
} }
} }

View File

@ -94,7 +94,7 @@ namespace osu.Game.Screens.Menu
}, },
} }
}, },
bigRing = new Ring(OsuColour.FromHex(@"B6C5E9"), 0.85f), bigRing = new Ring(Color4Extensions.FromHex(@"B6C5E9"), 0.85f),
mediumRing = new Ring(Color4.White.Opacity(130), 0.7f), mediumRing = new Ring(Color4.White.Opacity(130), 0.7f),
smallRing = new Ring(Color4.White, 0.6f), smallRing = new Ring(Color4.White, 0.6f),
welcomeText = new OsuSpriteText welcomeText = new OsuSpriteText
@ -121,7 +121,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0, Height = 0,
Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160), Colour = Color4Extensions.FromHex(@"C6D8FF").Opacity(160),
}, },
foregroundFill = new Box foregroundFill = new Box
{ {
@ -139,28 +139,28 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Position = new Vector2(0, circle_offset), Position = new Vector2(0, circle_offset),
Colour = OsuColour.FromHex(@"AA92FF"), Colour = Color4Extensions.FromHex(@"AA92FF"),
}, },
blueCircle = new Circle blueCircle = new Circle
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
Position = new Vector2(-circle_offset, 0), Position = new Vector2(-circle_offset, 0),
Colour = OsuColour.FromHex(@"8FE5FE"), Colour = Color4Extensions.FromHex(@"8FE5FE"),
}, },
yellowCircle = new Circle yellowCircle = new Circle
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
Position = new Vector2(0, -circle_offset), Position = new Vector2(0, -circle_offset),
Colour = OsuColour.FromHex(@"FFD64C"), Colour = Color4Extensions.FromHex(@"FFD64C"),
}, },
pinkCircle = new Circle pinkCircle = new Circle
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Position = new Vector2(circle_offset, 0), Position = new Vector2(circle_offset, 0),
Colour = OsuColour.FromHex(@"e967a1"), Colour = Color4Extensions.FromHex(@"e967a1"),
}, },
}; };

View File

@ -259,11 +259,18 @@ namespace osu.Game.Screens.Menu
private class LazerLogo : CompositeDrawable private class LazerLogo : CompositeDrawable
{ {
private readonly Stream videoStream;
public LazerLogo(Stream videoStream) public LazerLogo(Stream videoStream)
{ {
this.videoStream = videoStream;
Size = new Vector2(960); Size = new Vector2(960);
}
InternalChild = new VideoSprite(videoStream) [BackgroundDependencyLoader]
private void load()
{
InternalChild = new VideoSprite(videoStream, false)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Clock = new FramedOffsetClock(Clock) { Offset = -logo_1 } Clock = new FramedOffsetClock(Clock) { Offset = -logo_1 }

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -14,7 +15,6 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osuTK; using osuTK;
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Menu
/// </summary> /// </summary>
public class OsuLogo : BeatSyncedContainer public class OsuLogo : BeatSyncedContainer
{ {
public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1"); public readonly Color4 OsuPink = Color4Extensions.FromHex(@"e967a1");
private const double transition_length = 300; private const double transition_length = 300;
@ -176,8 +176,8 @@ namespace osu.Game.Screens.Menu
triangles = new Triangles triangles = new Triangles
{ {
TriangleScale = 4, TriangleScale = 4,
ColourLight = OsuColour.FromHex(@"ff7db7"), ColourLight = Color4Extensions.FromHex(@"ff7db7"),
ColourDark = OsuColour.FromHex(@"de5b95"), ColourDark = Color4Extensions.FromHex(@"de5b95"),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
} }

View File

@ -2,6 +2,7 @@
// 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.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
@ -27,7 +28,7 @@ namespace osu.Game.Screens.Multi.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"545454"), Colour = Color4Extensions.FromHex(@"545454"),
}, },
}; };
} }

View File

@ -2,12 +2,12 @@
// 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.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Users; using osu.Game.Users;
using osu.Game.Users.Drawables; using osu.Game.Users.Drawables;
using osuTK; using osuTK;
@ -114,7 +114,7 @@ namespace osu.Game.Screens.Multi.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"27252d"), Colour = Color4Extensions.FromHex(@"27252d"),
}, },
avatar = new UpdateableAvatar { RelativeSizeAxes = Axes.Both }, avatar = new UpdateableAvatar { RelativeSizeAxes = Axes.Both },
}; };

View File

@ -2,6 +2,7 @@
// 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.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -30,7 +31,7 @@ namespace osu.Game.Screens.Multi
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"2f2043"), Colour = Color4Extensions.FromHex(@"2f2043"),
}, },
new Container new Container
{ {

View File

@ -134,7 +134,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"212121"), Colour = Color4Extensions.FromHex(@"212121"),
}, },
new StatusColouredContainer(transition_duration) new StatusColouredContainer(transition_duration)
{ {

Some files were not shown because too many files have changed in this diff Show More