Merge branch 'master' into taiko-fixes

This commit is contained in:
Dan Balasescu 2017-04-06 16:23:22 +09:00 committed by GitHub
commit 6fc1384927
36 changed files with 660 additions and 568 deletions

View File

@ -0,0 +1,65 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Testing;
using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseInGameOverlays : TestCase
{
public override string Description => @"Tests pause and fail overlays";
private PauseOverlay pauseOverlay;
private FailOverlay failOverlay;
private int retryCount;
public override void Reset()
{
base.Reset();
pauseOverlay = new PauseOverlay
{
Depth = -1,
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
};
failOverlay = new FailOverlay
{
Depth = -1,
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
};
Add(pauseOverlay);
Add(failOverlay);
AddStep(@"Pause", delegate {
if(failOverlay.State == Visibility.Visible)
{
failOverlay.Hide();
}
pauseOverlay.Show();
});
AddStep("Fail", delegate {
if (pauseOverlay.State == Visibility.Visible)
{
pauseOverlay.Hide();
}
failOverlay.Show();
});
AddStep("Add Retry", delegate
{
retryCount++;
pauseOverlay.Retries = retryCount;
failOverlay.Retries = retryCount;
});
retryCount = 0;
}
}
}

View File

@ -1,38 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Logging;
using osu.Framework.Testing;
using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCasePauseOverlay : TestCase
{
public override string Description => @"Tests the pause overlay";
private PauseOverlay pauseOverlay;
private int retryCount;
public override void Reset()
{
base.Reset();
Add(pauseOverlay = new PauseOverlay
{
Depth = -1,
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit")
});
AddStep("Pause", pauseOverlay.Show);
AddStep("Add Retry", delegate
{
retryCount++;
pauseOverlay.Retries = retryCount;
});
retryCount = 0;
}
}
}

View File

@ -189,6 +189,7 @@
<Compile Include="Tests\TestCaseChatDisplay.cs" /> <Compile Include="Tests\TestCaseChatDisplay.cs" />
<Compile Include="Tests\TestCaseDrawings.cs" /> <Compile Include="Tests\TestCaseDrawings.cs" />
<Compile Include="Tests\TestCaseGamefield.cs" /> <Compile Include="Tests\TestCaseGamefield.cs" />
<Compile Include="Tests\TestCaseInGameOverlays.cs" />
<Compile Include="Tests\TestCaseMusicController.cs" /> <Compile Include="Tests\TestCaseMusicController.cs" />
<Compile Include="Tests\TestCaseNotificationManager.cs" /> <Compile Include="Tests\TestCaseNotificationManager.cs" />
<Compile Include="Tests\TestCasePlayer.cs" /> <Compile Include="Tests\TestCasePlayer.cs" />
@ -206,7 +207,6 @@
<Compile Include="VisualTestGame.cs" /> <Compile Include="VisualTestGame.cs" />
<Compile Include="Platform\TestStorage.cs" /> <Compile Include="Platform\TestStorage.cs" />
<Compile Include="Tests\TestCaseOptions.cs" /> <Compile Include="Tests\TestCaseOptions.cs" />
<Compile Include="Tests\TestCasePauseOverlay.cs" />
<Compile Include="Tests\TestCaseModSelectOverlay.cs" /> <Compile Include="Tests\TestCaseModSelectOverlay.cs" />
<Compile Include="Tests\TestCaseDialogOverlay.cs" /> <Compile Include="Tests\TestCaseDialogOverlay.cs" />
<Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" /> <Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" />

View File

@ -43,7 +43,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Slider return new Slider
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, Samples = original.Samples,
CurveObject = curveData, CurveObject = curveData,
Position = positionData?.Position ?? Vector2.Zero, Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false NewCombo = comboData?.NewCombo ?? false
@ -55,7 +55,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Spinner return new Spinner
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, Samples = original.Samples,
Position = new Vector2(512, 384) / 2, Position = new Vector2(512, 384) / 2,
EndTime = endTimeData.EndTime EndTime = endTimeData.EndTime
}; };
@ -64,7 +64,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new HitCircle return new HitCircle
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, Samples = original.Samples,
Position = positionData?.Position ?? Vector2.Zero, Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false NewCombo = comboData?.NewCombo ?? false
}; };

View File

@ -67,7 +67,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ComboIndex = s.ComboIndex, ComboIndex = s.ComboIndex,
Scale = s.Scale, Scale = s.Scale,
ComboColour = s.ComboColour, ComboColour = s.ComboColour,
Sample = s.Sample, Samples = s.Samples,
}), }),
}; };
@ -111,7 +111,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
if (repeat > currentRepeat) if (repeat > currentRepeat)
{ {
if (repeat < slider.RepeatCount && ball.Tracking) if (repeat < slider.RepeatCount && ball.Tracking)
PlaySample(); PlaySamples();
currentRepeat = repeat; currentRepeat = repeat;
} }

View File

@ -2,12 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements; using osu.Game.Modes.Osu.Judgements;
using OpenTK; using OpenTK;
@ -53,22 +49,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
}; };
} }
private SampleChannel sample;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
string sampleSet = (HitObject.Sample?.Set ?? SampleSet.Normal).ToString().ToLower();
sample = audio.Sample.Get($@"Gameplay/{sampleSet}-slidertick");
}
protected override void PlaySample()
{
sample?.Play();
}
protected override void CheckJudgement(bool userTriggered) protected override void CheckJudgement(bool userTriggered)
{ {
if (Judgement.TimeOffset >= 0) if (Judgement.TimeOffset >= 0)

View File

@ -2,13 +2,14 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK; using OpenTK;
using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Modes.Objects.Types; using osu.Game.Modes.Objects.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Modes.Objects; using osu.Game.Modes.Objects;
using osu.Game.Database; using osu.Game.Database;
using System.Linq;
using osu.Game.Audio;
namespace osu.Game.Modes.Osu.Objects namespace osu.Game.Modes.Osu.Objects
{ {
@ -95,11 +96,12 @@ namespace osu.Game.Modes.Osu.Objects
StackHeight = StackHeight, StackHeight = StackHeight,
Scale = Scale, Scale = Scale,
ComboColour = ComboColour, ComboColour = ComboColour,
Sample = new HitSampleInfo Samples = Samples.Select(s => new SampleInfo
{ {
Type = SampleType.None, Bank = s.Bank,
Set = SampleSet.Soft, Name = @"slidertick",
}, Volume = s.Volume
}).ToList()
}; };
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects; using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Types; using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Taiko.Objects; using osu.Game.Modes.Taiko.Objects;
@ -11,6 +10,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.IO.Serialization; using osu.Game.IO.Serialization;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Beatmaps namespace osu.Game.Modes.Taiko.Beatmaps
{ {
@ -62,9 +62,9 @@ namespace osu.Game.Modes.Taiko.Beatmaps
var endTimeData = obj as IHasEndTime; var endTimeData = obj as IHasEndTime;
// Old osu! used hit sounding to determine various hit type information // Old osu! used hit sounding to determine various hit type information
SampleType sample = obj.Sample?.Type ?? SampleType.None; List<SampleInfo> samples = obj.Samples;
bool strong = (sample & SampleType.Finish) > 0; bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH);
if (distanceData != null) if (distanceData != null)
{ {
@ -103,7 +103,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new CentreHit yield return new CentreHit
{ {
StartTime = j, StartTime = j,
Sample = obj.Sample, Samples = obj.Samples,
IsStrong = strong, IsStrong = strong,
}; };
} }
@ -113,7 +113,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new DrumRoll yield return new DrumRoll
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, Samples = obj.Samples,
IsStrong = strong, IsStrong = strong,
Duration = taikoDuration, Duration = taikoDuration,
TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4, TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4,
@ -127,7 +127,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new Swell yield return new Swell
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, Samples = obj.Samples,
IsStrong = strong, IsStrong = strong,
Duration = endTimeData.Duration, Duration = endTimeData.Duration,
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier), RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
@ -135,23 +135,23 @@ namespace osu.Game.Modes.Taiko.Beatmaps
} }
else else
{ {
bool isCentre = (sample & ~(SampleType.Finish | SampleType.Normal)) == 0; bool isRim = samples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE);
if (isCentre) if (isRim)
{ {
yield return new CentreHit yield return new RimHit
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, Samples = obj.Samples,
IsStrong = strong, IsStrong = strong,
}; };
} }
else else
{ {
yield return new RimHit yield return new CentreHit
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, Samples = obj.Samples,
IsStrong = strong, IsStrong = strong,
}; };
} }

View File

@ -1,13 +1,13 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types; using osu.Game.Modes.Objects.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Objects namespace osu.Game.Modes.Taiko.Objects
{ {
@ -82,11 +82,12 @@ namespace osu.Game.Modes.Taiko.Objects
TickSpacing = tickSpacing, TickSpacing = tickSpacing,
StartTime = t, StartTime = t,
IsStrong = IsStrong, IsStrong = IsStrong,
Sample = new HitSampleInfo Samples = Samples.Select(s => new SampleInfo
{ {
Type = SampleType.None, Bank = s.Bank,
Set = SampleSet.Soft Name = @"slidertick",
} Volume = s.Volume
}).ToList()
}); });
first = false; first = false;

View File

@ -6,11 +6,12 @@ using NUnit.Framework;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes; using osu.Game.Modes;
using osu.Game.Tests.Resources; using osu.Game.Tests.Resources;
using osu.Game.Modes.Osu; using osu.Game.Modes.Osu;
using osu.Game.Modes.Objects.Legacy; using osu.Game.Modes.Objects.Legacy;
using System.Linq;
using osu.Game.Audio;
namespace osu.Game.Tests.Beatmaps.Formats namespace osu.Game.Tests.Beatmaps.Formats
{ {
@ -55,7 +56,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo; var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo;
Assert.AreEqual(0, beatmapInfo.AudioLeadIn); Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
Assert.AreEqual(false, beatmapInfo.Countdown); Assert.AreEqual(false, beatmapInfo.Countdown);
Assert.AreEqual(SampleSet.Soft, beatmapInfo.SampleSet);
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
Assert.AreEqual(false, beatmapInfo.SpecialStyle); Assert.AreEqual(false, beatmapInfo.SpecialStyle);
Assert.AreEqual(PlayMode.Osu, beatmapInfo.Mode); Assert.AreEqual(PlayMode.Osu, beatmapInfo.Mode);
@ -137,12 +137,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(slider); Assert.IsNotNull(slider);
Assert.AreEqual(new Vector2(192, 168), slider.Position); Assert.AreEqual(new Vector2(192, 168), slider.Position);
Assert.AreEqual(956, slider.StartTime); Assert.AreEqual(956, slider.StartTime);
Assert.AreEqual(SampleType.None, slider.Sample.Type); Assert.IsTrue(slider.Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
var hit = beatmap.HitObjects[1] as LegacyHit; var hit = beatmap.HitObjects[1] as LegacyHit;
Assert.IsNotNull(hit); Assert.IsNotNull(hit);
Assert.AreEqual(new Vector2(304, 56), hit.Position); Assert.AreEqual(new Vector2(304, 56), hit.Position);
Assert.AreEqual(1285, hit.StartTime); Assert.AreEqual(1285, hit.StartTime);
Assert.AreEqual(SampleType.Clap, hit.Sample.Type); Assert.IsTrue(hit.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
} }
} }
} }

View File

@ -0,0 +1,28 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Audio
{
public class SampleInfo
{
public const string HIT_WHISTLE = @"hitwhistle";
public const string HIT_FINISH = @"hitfinish";
public const string HIT_NORMAL = @"hitnormal";
public const string HIT_CLAP = @"hitclap";
/// <summary>
/// The bank to load the sample from.
/// </summary>
public string Bank;
/// <summary>
/// The name of the sample to load.
/// </summary>
public string Name;
/// <summary>
/// The sample volume.
/// </summary>
public int Volume;
}
}

View File

@ -6,7 +6,6 @@ using System.Globalization;
using System.IO; using System.IO;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Beatmaps.Events; using osu.Game.Beatmaps.Events;
using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Modes; using osu.Game.Modes;
using osu.Game.Modes.Objects; using osu.Game.Modes.Objects;
@ -31,6 +30,9 @@ namespace osu.Game.Beatmaps.Formats
// TODO: Not sure how far back to go, or differences between versions // TODO: Not sure how far back to go, or differences between versions
} }
private LegacySampleBank defaultSampleBank;
private int defaultSampleVolume = 100;
private readonly int beatmapVersion; private readonly int beatmapVersion;
public OsuLegacyDecoder() public OsuLegacyDecoder()
@ -73,7 +75,10 @@ namespace osu.Game.Beatmaps.Formats
beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1; beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1;
break; break;
case @"SampleSet": case @"SampleSet":
beatmap.BeatmapInfo.SampleSet = (SampleSet)Enum.Parse(typeof(SampleSet), val); defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), val);
break;
case @"SampleVolume":
defaultSampleVolume = int.Parse(val);
break; break;
case @"StackLeniency": case @"StackLeniency":
beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo); beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo);
@ -203,28 +208,56 @@ namespace osu.Game.Beatmaps.Formats
private void handleTimingPoints(Beatmap beatmap, string val) private void handleTimingPoints(Beatmap beatmap, string val)
{ {
ControlPoint cp = null;
string[] split = val.Split(','); string[] split = val.Split(',');
if (split.Length > 2) double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
if (split.Length >= 3)
timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]);
LegacySampleBank sampleSet = defaultSampleBank;
if (split.Length >= 4)
sampleSet = (LegacySampleBank)int.Parse(split[3]);
//SampleBank sampleBank = SampleBank.Default;
//if (split.Length >= 5)
// sampleBank = (SampleBank)int.Parse(split[4]);
int sampleVolume = defaultSampleVolume;
if (split.Length >= 6)
sampleVolume = int.Parse(split[5]);
bool timingChange = true;
if (split.Length >= 7)
timingChange = split[6][0] == '1';
bool kiaiMode = false;
bool omitFirstBarSignature = false;
if (split.Length >= 8)
{ {
int effectFlags = split.Length > 7 ? Convert.ToInt32(split[7], NumberFormatInfo.InvariantInfo) : 0; int effectFlags = int.Parse(split[7]);
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo); kiaiMode = (effectFlags & 1) > 0;
cp = new ControlPoint omitFirstBarSignature = (effectFlags & 8) > 0;
{
Time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo),
BeatLength = beatLength > 0 ? beatLength : 0,
SpeedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1,
TimingChange = split.Length <= 6 || split[6][0] == '1',
KiaiMode = (effectFlags & 1) > 0,
OmitFirstBarLine = (effectFlags & 8) > 0,
TimeSignature = (TimeSignatures)int.Parse(split[2])
};
} }
if (cp != null) string stringSampleSet = sampleSet.ToString().ToLower();
beatmap.TimingInfo.ControlPoints.Add(cp); if (stringSampleSet == @"none")
stringSampleSet = @"normal";
beatmap.TimingInfo.ControlPoints.Add(new ControlPoint
{
Time = time,
BeatLength = beatLength,
SpeedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1,
TimingChange = timingChange,
TimeSignature = timeSignature,
SampleBank = stringSampleSet,
SampleVolume = sampleVolume,
KiaiMode = kiaiMode,
OmitFirstBarLine = omitFirstBarSignature
});
} }
private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours) private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
@ -271,7 +304,7 @@ namespace osu.Game.Beatmaps.Formats
{ {
beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion;
HitObjectParser parser = null; HitObjectParser parser = new LegacyHitObjectParser();
Section section = Section.None; Section section = Section.None;
bool hasCustomColours = false; bool hasCustomColours = false;
@ -305,7 +338,6 @@ namespace osu.Game.Beatmaps.Formats
{ {
case Section.General: case Section.General:
handleGeneral(beatmap, key, val); handleGeneral(beatmap, key, val);
parser = new LegacyHitObjectParser();
break; break;
case Section.Editor: case Section.Editor:
handleEditor(beatmap, key, val); handleEditor(beatmap, key, val);
@ -326,7 +358,7 @@ namespace osu.Game.Beatmaps.Formats
handleColours(beatmap, key, val, ref hasCustomColours); handleColours(beatmap, key, val, ref hasCustomColours);
break; break;
case Section.HitObjects: case Section.HitObjects:
var obj = parser?.Parse(val); var obj = parser.Parse(val);
if (obj != null) if (obj != null)
beatmap.HitObjects.Add(obj); beatmap.HitObjects.Add(obj);
@ -335,5 +367,13 @@ namespace osu.Game.Beatmaps.Formats
} }
} }
} }
internal enum LegacySampleBank
{
None = 0,
Normal = 1,
Soft = 2,
Drum = 3
}
} }
} }

View File

@ -1,10 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
public class HitSampleInfo : SampleInfo
{
public SampleType Type { get; set; }
}
}

View File

@ -1,12 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
public enum SampleBank
{
Default = 0,
Custom1 = 1,
Custom2 = 2
}
}

View File

@ -1,11 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
public class SampleInfo
{
public SampleBank Bank;
public SampleSet Set;
}
}

View File

@ -1,13 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
public enum SampleSet
{
None = 0,
Normal = 1,
Soft = 2,
Drum = 3
}
}

View File

@ -1,17 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Beatmaps.Samples
{
[Flags]
public enum SampleType
{
None = 0,
Normal = 1,
Whistle = 2,
Finish = 4,
Clap = 8
};
}

View File

@ -5,6 +5,8 @@ namespace osu.Game.Beatmaps.Timing
{ {
public class ControlPoint public class ControlPoint
{ {
public string SampleBank;
public int SampleVolume;
public TimeSignatures TimeSignature; public TimeSignatures TimeSignature;
public double Time; public double Time;
public double BeatLength = 500; public double BeatLength = 500;

View File

@ -1,12 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Samples;
namespace osu.Game.Beatmaps.Timing
{
public class SampleChange : ControlPoint
{
public SampleInfo Sample;
}
}

View File

@ -1,15 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Timing
{
internal class TimingChange : ControlPoint
{
public TimingChange(double beatLength)
{
BeatLength = beatLength;
}
public double BPM => 60000 / BeatLength;
}
}

View File

@ -35,6 +35,7 @@ namespace osu.Game.Configuration
Set(OsuConfig.MenuParallax, true); Set(OsuConfig.MenuParallax, true);
Set(OsuConfig.ShowInterface, true);
Set(OsuConfig.KeyOverlay, false); Set(OsuConfig.KeyOverlay, false);
//todo: implement all settings below this line (remove the Disabled set when doing so). //todo: implement all settings below this line (remove the Disabled set when doing so).
@ -89,7 +90,6 @@ namespace osu.Game.Configuration
Set(OsuConfig.LastVersionPermissionsFailed, string.Empty).Disabled = true; Set(OsuConfig.LastVersionPermissionsFailed, string.Empty).Disabled = true;
Set(OsuConfig.LoadSubmittedThread, true).Disabled = true; Set(OsuConfig.LoadSubmittedThread, true).Disabled = true;
Set(OsuConfig.LobbyPlayMode, -1).Disabled = true; Set(OsuConfig.LobbyPlayMode, -1).Disabled = true;
Set(OsuConfig.ShowInterface, true).Disabled = true;
Set(OsuConfig.ShowInterfaceDuringRelax, false).Disabled = true; Set(OsuConfig.ShowInterfaceDuringRelax, false).Disabled = true;
Set(OsuConfig.LobbyShowExistingOnly, false).Disabled = true; Set(OsuConfig.LobbyShowExistingOnly, false).Disabled = true;
Set(OsuConfig.LobbyShowFriendsOnly, false).Disabled = true; Set(OsuConfig.LobbyShowFriendsOnly, false).Disabled = true;

View File

@ -49,7 +49,6 @@ namespace osu.Game.Database
// General // General
public int AudioLeadIn { get; set; } public int AudioLeadIn { get; set; }
public bool Countdown { get; set; } public bool Countdown { get; set; }
public SampleSet SampleSet { get; set; }
public float StackLeniency { get; set; } public float StackLeniency { get; set; }
public bool SpecialStyle { get; set; } public bool SpecialStyle { get; set; }
public PlayMode Mode { get; set; } public PlayMode Mode { get; set; }

View File

@ -7,11 +7,11 @@ using osu.Framework;
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.Game.Beatmaps.Samples;
using osu.Game.Modes.Judgements; using osu.Game.Modes.Judgements;
using Container = osu.Framework.Graphics.Containers.Container; using Container = osu.Framework.Graphics.Containers.Container;
using osu.Game.Modes.Objects.Types; using osu.Game.Modes.Objects.Types;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Audio;
namespace osu.Game.Modes.Objects.Drawables namespace osu.Game.Modes.Objects.Drawables
{ {
@ -45,15 +45,15 @@ namespace osu.Game.Modes.Objects.Drawables
UpdateState(state); UpdateState(state);
if (State == ArmedState.Hit) if (State == ArmedState.Hit)
PlaySample(); PlaySamples();
} }
} }
protected SampleChannel Sample; protected List<SampleChannel> Samples = new List<SampleChannel>();
protected virtual void PlaySample() protected void PlaySamples()
{ {
Sample?.Play(); Samples.ForEach(s => s?.Play());
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -156,13 +156,16 @@ namespace osu.Game.Modes.Objects.Drawables
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
SampleType type = HitObject.Sample?.Type ?? SampleType.None; foreach (SampleInfo sample in HitObject.Samples)
if (type == SampleType.None) {
type = SampleType.Normal; SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}");
SampleSet sampleSet = HitObject.Sample?.Set ?? SampleSet.Normal; if (channel == null)
continue;
Sample = audio.Sample.Get($@"Gameplay/{sampleSet.ToString().ToLower()}-hit{type.ToString().ToLower()}"); channel.Volume.Value = sample.Volume;
Samples.Add(channel);
}
} }
private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects; private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects;

View File

@ -1,9 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Samples; using osu.Game.Audio;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Database; using osu.Game.Database;
using System.Collections.Generic;
namespace osu.Game.Modes.Objects namespace osu.Game.Modes.Objects
{ {
@ -21,15 +22,31 @@ namespace osu.Game.Modes.Objects
public double StartTime { get; set; } public double StartTime { get; set; }
/// <summary> /// <summary>
/// The sample to be played when this HitObject is hit. /// The samples to be played when this hit object is hit.
/// </summary> /// </summary>
public HitSampleInfo Sample { get; set; } public List<SampleInfo> Samples = new List<SampleInfo>();
/// <summary> /// <summary>
/// Applies default values to this HitObject. /// Applies default values to this HitObject.
/// </summary> /// </summary>
/// <param name="difficulty">The difficulty settings to use.</param> /// <param name="difficulty">The difficulty settings to use.</param>
/// <param name="timing">The timing settings to use.</param> /// <param name="timing">The timing settings to use.</param>
public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty) { } public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
ControlPoint overridePoint;
ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
foreach (var sample in Samples)
{
if (sample.Volume == 0)
sample.Volume = (overridePoint ?? timingPoint)?.SampleVolume ?? 0;
// If the bank is not assigned a name, assign it from the control point
if (!string.IsNullOrEmpty(sample.Bank))
continue;
sample.Bank = (overridePoint ?? timingPoint)?.SampleBank ?? @"normal";
}
}
} }
} }

View File

@ -2,12 +2,13 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK; using OpenTK;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types; using osu.Game.Modes.Objects.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using osu.Game.Modes.Objects.Legacy; using osu.Game.Modes.Objects.Legacy;
using osu.Game.Beatmaps.Formats;
using osu.Game.Audio;
namespace osu.Game.Modes.Objects namespace osu.Game.Modes.Objects
{ {
@ -20,6 +21,10 @@ namespace osu.Game.Modes.Objects
bool combo = type.HasFlag(LegacyHitObjectType.NewCombo); bool combo = type.HasFlag(LegacyHitObjectType.NewCombo);
type &= ~LegacyHitObjectType.NewCombo; type &= ~LegacyHitObjectType.NewCombo;
int sampleVolume = 0;
string normalSampleBank = null;
string addSampleBank = null;
HitObject result; HitObject result;
if ((type & LegacyHitObjectType.Circle) > 0) if ((type & LegacyHitObjectType.Circle) > 0)
@ -29,6 +34,9 @@ namespace osu.Game.Modes.Objects
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])), Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
NewCombo = combo NewCombo = combo
}; };
if (split.Length > 5)
readCustomSampleBanks(split[5], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
} }
else if ((type & LegacyHitObjectType.Slider) > 0) else if ((type & LegacyHitObjectType.Slider) > 0)
{ {
@ -84,6 +92,9 @@ namespace osu.Game.Modes.Objects
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])), Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
NewCombo = combo NewCombo = combo
}; };
if (split.Length > 10)
readCustomSampleBanks(split[10], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
} }
else if ((type & LegacyHitObjectType.Spinner) > 0) else if ((type & LegacyHitObjectType.Spinner) > 0)
{ {
@ -91,10 +102,17 @@ namespace osu.Game.Modes.Objects
{ {
EndTime = Convert.ToDouble(split[5], CultureInfo.InvariantCulture) EndTime = Convert.ToDouble(split[5], CultureInfo.InvariantCulture)
}; };
if (split.Length > 6)
readCustomSampleBanks(split[6], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
} }
else if ((type & LegacyHitObjectType.Hold) > 0) else if ((type & LegacyHitObjectType.Hold) > 0)
{ {
// Note: Hold is generated by BMS converts // Note: Hold is generated by BMS converts
// Todo: Apparently end time is determined by samples??
// Shouldn't need implementation until mania
result = new LegacyHold result = new LegacyHold
{ {
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])), Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
@ -105,15 +123,82 @@ namespace osu.Game.Modes.Objects
throw new InvalidOperationException($@"Unknown hit object type {type}"); throw new InvalidOperationException($@"Unknown hit object type {type}");
result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture); result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);
result.Sample = new HitSampleInfo
{
Type = (SampleType)int.Parse(split[4]),
Set = SampleSet.Soft,
};
// TODO: "addition" field var soundType = (LegacySoundType)int.Parse(split[4]);
result.Samples.Add(new SampleInfo
{
Bank = normalSampleBank,
Name = SampleInfo.HIT_NORMAL,
Volume = sampleVolume
});
if ((soundType & LegacySoundType.Finish) > 0)
{
result.Samples.Add(new SampleInfo
{
Bank = addSampleBank,
Name = SampleInfo.HIT_FINISH,
Volume = sampleVolume
});
}
if ((soundType & LegacySoundType.Whistle) > 0)
{
result.Samples.Add(new SampleInfo
{
Bank = addSampleBank,
Name = SampleInfo.HIT_WHISTLE,
Volume = sampleVolume
});
}
if ((soundType & LegacySoundType.Clap) > 0)
{
result.Samples.Add(new SampleInfo
{
Bank = addSampleBank,
Name = SampleInfo.HIT_CLAP,
Volume = sampleVolume
});
}
return result; return result;
} }
private void readCustomSampleBanks(string str, ref string normalSampleBank, ref string addSampleBank, ref int sampleVolume)
{
if (string.IsNullOrEmpty(str))
return;
string[] split = str.Split(':');
var bank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[0]);
var addbank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[1]);
// Let's not implement this for now, because this doesn't fit nicely into the bank structure
//string sampleFile = split2.Length > 4 ? split2[4] : string.Empty;
string stringBank = bank.ToString().ToLower();
if (stringBank == @"none")
stringBank = null;
string stringAddBank = addbank.ToString().ToLower();
if (stringAddBank == @"none")
stringAddBank = null;
normalSampleBank = stringBank;
addSampleBank = stringAddBank;
sampleVolume = split.Length > 3 ? int.Parse(split[3]) : 0;
}
[Flags]
private enum LegacySoundType
{
None = 0,
Normal = 1,
Whistle = 2,
Finish = 4,
Clap = 8
}
} }
} }

View File

@ -9,11 +9,18 @@ using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Modes.Scoring; using osu.Game.Modes.Scoring;
using osu.Framework.Input;
using OpenTK.Input;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Game.Modes.UI namespace osu.Game.Modes.UI
{ {
public abstract class HudOverlay : Container public abstract class HudOverlay : Container
{ {
private const int duration = 100;
private readonly Container content;
public readonly KeyCounterCollection KeyCounter; public readonly KeyCounterCollection KeyCounter;
public readonly ComboCounter ComboCounter; public readonly ComboCounter ComboCounter;
public readonly ScoreCounter ScoreCounter; public readonly ScoreCounter ScoreCounter;
@ -21,6 +28,9 @@ namespace osu.Game.Modes.UI
public readonly HealthDisplay HealthDisplay; public readonly HealthDisplay HealthDisplay;
private Bindable<bool> showKeyCounter; private Bindable<bool> showKeyCounter;
private Bindable<bool> showHud;
private static bool hasShownNotificationOnce;
protected abstract KeyCounterCollection CreateKeyCounter(); protected abstract KeyCounterCollection CreateKeyCounter();
protected abstract ComboCounter CreateComboCounter(); protected abstract ComboCounter CreateComboCounter();
@ -32,28 +42,53 @@ namespace osu.Game.Modes.UI
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Children = new Drawable[] Add(content = new Container
{ {
KeyCounter = CreateKeyCounter(), RelativeSizeAxes = Axes.Both,
ComboCounter = CreateComboCounter(),
ScoreCounter = CreateScoreCounter(), Children = new Drawable[]
AccuracyCounter = CreateAccuracyCounter(), {
HealthDisplay = CreateHealthDisplay(), KeyCounter = CreateKeyCounter(),
}; ComboCounter = CreateComboCounter(),
ScoreCounter = CreateScoreCounter(),
AccuracyCounter = CreateAccuracyCounter(),
HealthDisplay = CreateHealthDisplay(),
}
});
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config) private void load(OsuConfigManager config, NotificationManager notificationManager)
{ {
showKeyCounter = config.GetBindable<bool>(OsuConfig.KeyOverlay); showKeyCounter = config.GetBindable<bool>(OsuConfig.KeyOverlay);
showKeyCounter.ValueChanged += visibility => showKeyCounter.ValueChanged += keyCounterVisibility =>
{ {
if (visibility) if (keyCounterVisibility)
KeyCounter.Show(); KeyCounter.FadeIn(duration);
else else
KeyCounter.Hide(); KeyCounter.FadeOut(duration);
}; };
showKeyCounter.TriggerChange(); showKeyCounter.TriggerChange();
showHud = config.GetBindable<bool>(OsuConfig.ShowInterface);
showHud.ValueChanged += hudVisibility =>
{
if (hudVisibility)
content.FadeIn(duration);
else
content.FadeOut(duration);
};
showHud.TriggerChange();
if (!showHud && !hasShownNotificationOnce)
{
hasShownNotificationOnce = true;
notificationManager?.Post(new SimpleNotification
{
Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab."
});
}
} }
public void BindProcessor(ScoreProcessor processor) public void BindProcessor(ScoreProcessor processor)
@ -68,5 +103,22 @@ namespace osu.Game.Modes.UI
{ {
hitRenderer.InputManager.Add(KeyCounter.GetReceptor()); hitRenderer.InputManager.Add(KeyCounter.GetReceptor());
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat) return false;
if (state.Keyboard.ShiftPressed)
{
switch (args.Key)
{
case Key.Tab:
showHud.Value = !showHud.Value;
return true;
}
}
return base.OnKeyDown(state, args);
}
} }
} }

View File

@ -39,6 +39,11 @@ namespace osu.Game.Overlays.Options.Sections.Gameplay
Bindable = (BindableDouble)config.GetBindable<double>(OsuConfig.ScoreMeterScale) Bindable = (BindableDouble)config.GetBindable<double>(OsuConfig.ScoreMeterScale)
}, },
new OsuCheckbox new OsuCheckbox
{
LabelText = "Show score overlay",
Bindable = config.GetBindable<bool>(OsuConfig.ShowInterface)
},
new OsuCheckbox
{ {
LabelText = "Always show key overlay", LabelText = "Always show key overlay",
Bindable = config.GetBindable<bool>(OsuConfig.KeyOverlay) Bindable = config.GetBindable<bool>(OsuConfig.KeyOverlay)

View File

@ -1,42 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens;
using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Backgrounds;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Screens.Play
{
internal class FailDialog : OsuScreen
{
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap);
private static readonly Vector2 background_blur = new Vector2(20);
public FailDialog()
{
Add(new OsuSpriteText
{
Text = "You failed!",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
TextSize = 50
});
}
protected override void OnEntering(Screen last)
{
base.OnEntering(last);
Background.Schedule(() => (Background as BackgroundScreenBeatmap)?.BlurTo(background_blur, 1000));
}
protected override bool OnExiting(Screen next)
{
Background.Schedule(() => Background.FadeColour(Color4.White, 500));
return base.OnExiting(next);
}
}
}

View File

@ -0,0 +1,37 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK.Input;
using osu.Game.Graphics;
using OpenTK.Graphics;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Play
{
public class FailOverlay : MenuOverlay
{
public override string Header => "failed";
public override string Description => "you're dead, try again?";
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.Escape)
{
if (State == Visibility.Hidden) return false;
OnQuit();
return true;
}
return base.OnKeyDown(state, args);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AddButton("Retry", colours.YellowDark, OnRetry);
AddButton("Quit", new Color4(170, 27, 39, 255), OnQuit);
}
}
}

View File

@ -0,0 +1,194 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Play.Pause;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Graphics;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Play
{
public abstract class MenuOverlay : OverlayContainer
{
private const int transition_duration = 200;
private const int button_height = 70;
private const float background_alpha = 0.75f;
protected override bool HideOnEscape => false;
public Action OnRetry;
public Action OnQuit;
public abstract string Header { get; }
public abstract string Description { get; }
private FillFlowContainer buttons;
public int Retries
{
set
{
if (retryCounterContainer != null)
{
// "You've retried 1,065 times in this session"
// "You've retried 1 time in this session"
retryCounterContainer.Children = new Drawable[]
{
new OsuSpriteText
{
Text = "You've retried ",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $"{value:n0}",
Font = @"Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $" time{(value == 1 ? "" : "s")} in this session",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
}
};
}
}
}
private FillFlowContainer retryCounterContainer;
public override bool HandleInput => State == Visibility.Visible;
protected override void PopIn() => FadeIn(transition_duration, EasingTypes.In);
protected override void PopOut() => FadeOut(transition_duration, EasingTypes.In);
// Don't let mouse down events through the overlay or people can click circles while paused.
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
protected override bool OnMouseMove(InputState state) => true;
protected void AddButton(string text, Color4 colour, Action action)
{
buttons.Add(new PauseButton
{
Text = text,
ButtonColour = colour,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate {
action?.Invoke();
Hide();
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = background_alpha,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 50),
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Children = new Drawable[]
{
new FillFlowContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Children = new Drawable[]
{
new OsuSpriteText
{
Text = Header,
Font = @"Exo2.0-Medium",
Spacing = new Vector2(5, 0),
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
TextSize = 30,
Colour = colours.Yellow,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
},
new OsuSpriteText
{
Text = Description,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
}
}
},
buttons = new FillFlowContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Masking = true,
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.6f),
Radius = 50
},
},
retryCounterContainer = new FillFlowContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
}
}
},
new PauseProgressBar
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Width = 1f
}
};
Retries = 0;
}
protected MenuOverlay()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
}
}
}

View File

@ -4,23 +4,16 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using OpenTK.Graphics;
namespace osu.Game.Screens.Play.Pause namespace osu.Game.Screens.Play.Pause
{ {
public class QuitButton : DialogButton public class PauseButton : DialogButton
{ {
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
ButtonColour = new Color4(170, 27, 39, 255); // The red from the design isn't in the palette so it's used directly
SampleHover = audio.Sample.Get(@"Menu/menuclick"); SampleHover = audio.Sample.Get(@"Menu/menuclick");
SampleClick = audio.Sample.Get(@"Menu/menuback"); SampleClick = audio.Sample.Get(@"Menu/menuback");
} }
public QuitButton()
{
Text = @"Quit to Main Menu";
}
} }
} }

View File

@ -1,26 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Play.Pause
{
public class ResumeButton : DialogButton
{
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
{
ButtonColour = colours.Green;
SampleHover = audio.Sample.Get(@"Menu/menuclick");
SampleClick = audio.Sample.Get(@"Menu/menuback");
}
public ResumeButton()
{
Text = @"Continue";
}
}
}

View File

@ -1,26 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Play.Pause
{
public class RetryButton : DialogButton
{
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
{
ButtonColour = colours.YellowDark;
SampleHover = audio.Sample.Get(@"Menu/menuclick");
SampleClick = audio.Sample.Get(@"Menu/menu-play-click");
}
public RetryButton()
{
Text = @"Retry";
}
}
}

View File

@ -2,89 +2,28 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Play.Pause;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input; using OpenTK.Input;
using osu.Framework.Graphics.Containers;
using OpenTK.Graphics;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
public class PauseOverlay : OverlayContainer public class PauseOverlay : MenuOverlay
{ {
private const int transition_duration = 200;
private const int button_height = 70;
private const float background_alpha = 0.75f;
protected override bool HideOnEscape => false;
public Action OnResume; public Action OnResume;
public Action OnRetry;
public Action OnQuit;
public int Retries public override string Header => "paused";
{ public override string Description => "you're not going to do what i think you're going to do, are ya?";
set
{
if (retryCounterContainer != null)
{
// "You've retried 1,065 times in this session"
// "You've retried 1 time in this session"
retryCounterContainer.Children = new Drawable[]
{
new OsuSpriteText
{
Text = "You've retried ",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $"{value:n0}",
Font = @"Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $" time{(value == 1 ? "" : "s")} in this session",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
}
};
}
}
}
private FillFlowContainer retryCounterContainer;
public override bool HandleInput => State == Visibility.Visible;
protected override void PopIn() => FadeIn(transition_duration, EasingTypes.In);
protected override void PopOut() => FadeOut(transition_duration, EasingTypes.In);
// Don't let mouse down events through the overlay or people can click circles while paused.
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
protected override bool OnMouseMove(InputState state) => true;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{ {
if (args.Key == Key.Escape) if (args.Key == Key.Escape)
{ {
if (State == Visibility.Hidden) return false; if (State == Visibility.Hidden) return false;
resume(); OnResume();
return true; return true;
} }
@ -94,131 +33,10 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
Children = new Drawable[] AddButton("Continue", colours.Green, OnResume);
{ AddButton("Retry", colours.YellowDark, OnRetry);
new Box AddButton("Quit", new Color4(170, 27, 39, 255), OnQuit);
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = background_alpha,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 50),
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Children = new Drawable[]
{
new FillFlowContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Children = new Drawable[]
{
new OsuSpriteText
{
Text = @"paused",
Font = @"Exo2.0-Medium",
Spacing = new Vector2(5, 0),
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
TextSize = 30,
Colour = colours.Yellow,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
},
new OsuSpriteText
{
Text = @"you're not going to do what i think you're going to do, are ya?",
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
}
}
},
new FillFlowContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Masking = true,
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.6f),
Radius = 50
},
Children = new Drawable[]
{
new ResumeButton
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = resume
},
new RetryButton
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
OnRetry?.Invoke();
Hide();
}
},
new QuitButton
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
OnQuit?.Invoke();
Hide();
}
}
}
},
retryCounterContainer = new FillFlowContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
}
}
},
new PauseProgressBar
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Width = 1f
}
};
Retries = 0;
}
private void resume()
{
OnResume?.Invoke();
Hide();
}
public PauseOverlay()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
} }
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK; using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
@ -31,12 +30,14 @@ namespace osu.Game.Screens.Play
internal override bool ShowOverlays => false; internal override bool ShowOverlays => false;
internal override bool HasLocalCursorDisplayed => !IsPaused && HitRenderer.ProvidingUserCursor; internal override bool HasLocalCursorDisplayed => !IsPaused && !HasFailed && HitRenderer.ProvidingUserCursor;
public BeatmapInfo BeatmapInfo; public BeatmapInfo BeatmapInfo;
public bool IsPaused { get; private set; } public bool IsPaused { get; private set; }
public bool HasFailed { get; private set; }
public int RestartCount; public int RestartCount;
private const double pause_cooldown = 1000; private const double pause_cooldown = 1000;
@ -56,6 +57,7 @@ namespace osu.Game.Screens.Play
private HudOverlay hudOverlay; private HudOverlay hudOverlay;
private PauseOverlay pauseOverlay; private PauseOverlay pauseOverlay;
private FailOverlay failOverlay;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config) private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config)
@ -116,20 +118,6 @@ namespace osu.Game.Screens.Play
hudOverlay = new StandardHudOverlay(); hudOverlay = new StandardHudOverlay();
hudOverlay.KeyCounter.Add(ruleset.CreateGameplayKeys()); hudOverlay.KeyCounter.Add(ruleset.CreateGameplayKeys());
hudOverlay.BindProcessor(scoreProcessor); hudOverlay.BindProcessor(scoreProcessor);
pauseOverlay = new PauseOverlay
{
Depth = -1,
OnResume = delegate
{
Delay(400);
Schedule(Resume);
},
OnRetry = Restart,
OnQuit = Exit
};
hudOverlay.BindHitRenderer(HitRenderer); hudOverlay.BindHitRenderer(HitRenderer);
//bind HitRenderer to ScoreProcessor and ourselves (for a pass situation) //bind HitRenderer to ScoreProcessor and ourselves (for a pass situation)
@ -154,7 +142,21 @@ namespace osu.Game.Screens.Play
} }
}, },
hudOverlay, hudOverlay,
pauseOverlay pauseOverlay = new PauseOverlay
{
OnResume = delegate
{
Delay(400);
Schedule(Resume);
},
OnRetry = Restart,
OnQuit = Exit,
},
failOverlay = new FailOverlay
{
OnRetry = Restart,
OnQuit = Exit,
}
}; };
} }
@ -254,15 +256,13 @@ namespace osu.Game.Screens.Play
private void onFail() private void onFail()
{ {
Content.FadeColour(Color4.Red, 500);
sourceClock.Stop(); sourceClock.Stop();
Delay(500); Delay(500);
Schedule(delegate
{ HasFailed = true;
ValidForResume = false; failOverlay.Retries = RestartCount;
Push(new FailDialog()); failOverlay.Show();
});
} }
protected override void OnEntering(Screen last) protected override void OnEntering(Screen last)

View File

@ -71,6 +71,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Audio\SampleInfo.cs" />
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" /> <Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
<Compile Include="Beatmaps\DifficultyCalculator.cs" /> <Compile Include="Beatmaps\DifficultyCalculator.cs" />
<Compile Include="Beatmaps\IBeatmapCoverter.cs" /> <Compile Include="Beatmaps\IBeatmapCoverter.cs" />
@ -149,14 +150,7 @@
<Compile Include="Beatmaps\Drawables\Panel.cs" /> <Compile Include="Beatmaps\Drawables\Panel.cs" />
<Compile Include="Modes\Objects\Drawables\DrawableHitObject.cs" /> <Compile Include="Modes\Objects\Drawables\DrawableHitObject.cs" />
<Compile Include="Modes\Objects\HitObject.cs" /> <Compile Include="Modes\Objects\HitObject.cs" />
<Compile Include="Beatmaps\Samples\HitSampleInfo.cs" />
<Compile Include="Beatmaps\Samples\SampleBank.cs" />
<Compile Include="Beatmaps\Samples\SampleInfo.cs" />
<Compile Include="Beatmaps\Samples\SampleSet.cs" />
<Compile Include="Beatmaps\Samples\SampleType.cs" />
<Compile Include="Beatmaps\Timing\ControlPoint.cs" /> <Compile Include="Beatmaps\Timing\ControlPoint.cs" />
<Compile Include="Beatmaps\Timing\SampleChange.cs" />
<Compile Include="Beatmaps\Timing\TimingChange.cs" />
<Compile Include="Configuration\OsuConfigManager.cs" /> <Compile Include="Configuration\OsuConfigManager.cs" />
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" /> <Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
<Compile Include="Overlays\Notifications\Notification.cs" /> <Compile Include="Overlays\Notifications\Notification.cs" />
@ -199,8 +193,11 @@
<Compile Include="Screens\Multiplayer\Lobby.cs" /> <Compile Include="Screens\Multiplayer\Lobby.cs" />
<Compile Include="Screens\Multiplayer\Match.cs" /> <Compile Include="Screens\Multiplayer\Match.cs" />
<Compile Include="Screens\Multiplayer\MatchCreate.cs" /> <Compile Include="Screens\Multiplayer\MatchCreate.cs" />
<Compile Include="Screens\Play\FailDialog.cs" /> <Compile Include="Screens\Play\FailOverlay.cs" />
<Compile Include="Screens\Play\MenuOverlay.cs" />
<Compile Include="Screens\Play\KeyConversionInputManager.cs" /> <Compile Include="Screens\Play\KeyConversionInputManager.cs" />
<Compile Include="Screens\Play\PauseOverlay.cs" />
<Compile Include="Screens\Play\Pause\PauseButton.cs" />
<Compile Include="Screens\Play\PlayerInputManager.cs" /> <Compile Include="Screens\Play\PlayerInputManager.cs" />
<Compile Include="Screens\Play\PlayerLoader.cs" /> <Compile Include="Screens\Play\PlayerLoader.cs" />
<Compile Include="Screens\Play\ReplayPlayer.cs" /> <Compile Include="Screens\Play\ReplayPlayer.cs" />
@ -337,12 +334,8 @@
<Compile Include="Screens\Select\SearchTextBox.cs" /> <Compile Include="Screens\Select\SearchTextBox.cs" />
<Compile Include="Screens\Select\FooterButton.cs" /> <Compile Include="Screens\Select\FooterButton.cs" />
<Compile Include="Screens\Select\Footer.cs" /> <Compile Include="Screens\Select\Footer.cs" />
<Compile Include="Screens\Play\PauseOverlay.cs" />
<Compile Include="Screens\Play\Pause\PauseProgressBar.cs" /> <Compile Include="Screens\Play\Pause\PauseProgressBar.cs" />
<Compile Include="Screens\Play\Pause\PauseProgressGraph.cs" /> <Compile Include="Screens\Play\Pause\PauseProgressGraph.cs" />
<Compile Include="Screens\Play\Pause\ResumeButton.cs" />
<Compile Include="Screens\Play\Pause\RetryButton.cs" />
<Compile Include="Screens\Play\Pause\QuitButton.cs" />
<Compile Include="Overlays\Mods\ModSelectOverlay.cs" /> <Compile Include="Overlays\Mods\ModSelectOverlay.cs" />
<Compile Include="Modes\Mods\Mod.cs" /> <Compile Include="Modes\Mods\Mod.cs" />
<Compile Include="Overlays\Mods\ModButton.cs" /> <Compile Include="Overlays\Mods\ModButton.cs" />