1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 12:07:23 +08:00

Merge branch 'master' into code-sanity-update

This commit is contained in:
Huo Yaoyuan 2017-04-06 15:55:14 +08:00
commit f8f75430e4
43 changed files with 731 additions and 618 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\TestCaseDrawings.cs" />
<Compile Include="Tests\TestCaseGamefield.cs" />
<Compile Include="Tests\TestCaseInGameOverlays.cs" />
<Compile Include="Tests\TestCaseMusicController.cs" />
<Compile Include="Tests\TestCaseNotificationManager.cs" />
<Compile Include="Tests\TestCasePlayer.cs" />
@ -206,7 +207,6 @@
<Compile Include="VisualTestGame.cs" />
<Compile Include="Platform\TestStorage.cs" />
<Compile Include="Tests\TestCaseOptions.cs" />
<Compile Include="Tests\TestCasePauseOverlay.cs" />
<Compile Include="Tests\TestCaseModSelectOverlay.cs" />
<Compile Include="Tests\TestCaseDialogOverlay.cs" />
<Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" />

View File

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

View File

@ -67,7 +67,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ComboIndex = s.ComboIndex,
Scale = s.Scale,
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 < slider.RepeatCount && ball.Tracking)
PlaySample();
PlaySamples();
currentRepeat = repeat;
}

View File

@ -2,12 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
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)
{
if (Judgement.TimeOffset >= 0)

View File

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

View File

@ -2,16 +2,15 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Taiko.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.IO.Serialization;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Beatmaps
{
@ -41,9 +40,12 @@ namespace osu.Game.Modes.Taiko.Beatmaps
public Beatmap<TaikoHitObject> Convert(Beatmap original)
{
BeatmapInfo info = original.BeatmapInfo.DeepClone<BeatmapInfo>();
info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier;
return new Beatmap<TaikoHitObject>(original)
{
TimingInfo = original is LegacyBeatmap ? new LegacyTimingInfo(original.TimingInfo) : original.TimingInfo,
BeatmapInfo = info,
HitObjects = original.HitObjects.SelectMany(h => convertHitObject(h, original)).ToList()
};
}
@ -60,9 +62,9 @@ namespace osu.Game.Modes.Taiko.Beatmaps
var endTimeData = obj as IHasEndTime;
// 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)
{
@ -75,7 +77,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
double distance = distanceData.Distance * repeats * legacy_velocity_multiplier;
// The velocity of the taiko hit object - calculated as the velocity of a drum roll
double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength * legacy_velocity_multiplier;
double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
// The duration of the taiko hit object
double taikoDuration = distance / taikoVelocity;
@ -85,7 +87,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
speedAdjustedBeatLength /= speedAdjustment;
// The velocity of the osu! hit object - calculated as the velocity of a slider
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength * legacy_velocity_multiplier;
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
// The duration of the osu! hit object
double osuDuration = distance / osuVelocity;
@ -101,7 +103,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new CentreHit
{
StartTime = j,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
};
}
@ -111,7 +113,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new DrumRoll
{
StartTime = obj.StartTime,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
Duration = taikoDuration,
TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4,
@ -125,7 +127,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new Swell
{
StartTime = obj.StartTime,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
Duration = endTimeData.Duration,
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
@ -133,41 +135,25 @@ namespace osu.Game.Modes.Taiko.Beatmaps
}
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)
{
yield return new CentreHit
{
StartTime = obj.StartTime,
Sample = obj.Sample,
IsStrong = strong,
};
}
else
if (isRim)
{
yield return new RimHit
{
StartTime = obj.StartTime,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
};
}
}
}
private class LegacyTimingInfo : TimingInfo
{
public LegacyTimingInfo(TimingInfo original)
{
if (original is LegacyTimingInfo)
ControlPoints.AddRange(original.ControlPoints);
else
{
ControlPoints.AddRange(original.ControlPoints.Select(c => c.Clone()));
foreach (var c in ControlPoints)
c.SpeedMultiplier *= legacy_velocity_multiplier;
yield return new CentreHit
{
StartTime = obj.StartTime,
Samples = obj.Samples,
IsStrong = strong,
};
}
}
}

View File

@ -15,6 +15,8 @@ namespace osu.Game.Modes.Taiko.Judgements
/// </summary>
public override string MaxResultString => string.Empty;
public override bool AffectsCombo => false;
protected override int NumericResultForScore(TaikoHitResult result)
{
switch (result)

View File

@ -3,6 +3,7 @@
using osu.Game.Modes.Judgements;
using osu.Framework.Extensions;
using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Taiko.Judgements
{
@ -21,12 +22,12 @@ namespace osu.Game.Modes.Taiko.Judgements
/// <summary>
/// The result value for the combo portion of the score.
/// </summary>
public int ResultValueForScore => NumericResultForScore(TaikoResult);
public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(TaikoResult);
/// <summary>
/// The result value for the accuracy portion of the score.
/// </summary>
public int ResultValueForAccuracy => NumericResultForAccuracy(TaikoResult);
public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(TaikoResult);
/// <summary>
/// The maximum result value for the combo portion of the score.

View File

@ -1,13 +1,13 @@
// 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;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Objects
{
@ -82,11 +82,12 @@ namespace osu.Game.Modes.Taiko.Objects
TickSpacing = tickSpacing,
StartTime = t,
IsStrong = IsStrong,
Sample = new HitSampleInfo
Samples = Samples.Select(s => new SampleInfo
{
Type = SampleType.None,
Set = SampleSet.Soft
}
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList()
});
first = false;

View File

@ -39,7 +39,7 @@ namespace osu.Game.Modes.Taiko.Objects
{
base.ApplyDefaults(timing, difficulty);
ScrollTime = scroll_time * (timing.BeatLengthAt(StartTime) / 1000) / (difficulty.SliderMultiplier * timing.SpeedMultiplierAt(StartTime));
ScrollTime = scroll_time * (timing.BeatLengthAt(StartTime) * timing.SpeedMultiplierAt(StartTime) / 1000) / difficulty.SliderMultiplier;
ControlPoint overridePoint;
Kiai = timing.TimingPointAt(StartTime, out overridePoint).KiaiMode;

View File

@ -187,10 +187,6 @@ namespace osu.Game.Modes.Taiko.Scoring
if (!isTick)
totalHits++;
// Apply combo changes, must be done before the hit score is added
if (!isTick && judgement.Result == HitResult.Hit)
Combo.Value++;
// Apply score changes
addHitScore(judgement);
@ -261,7 +257,7 @@ namespace osu.Game.Modes.Taiko.Scoring
foreach (var j in Judgements)
{
scoreForAccuracy += j.ResultValueForAccuracy;
maxScoreForAccuracy = j.MaxResultValueForAccuracy;
maxScoreForAccuracy += j.MaxResultValueForAccuracy;
}
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;

View File

@ -6,11 +6,12 @@ using NUnit.Framework;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes;
using osu.Game.Tests.Resources;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Objects.Legacy;
using System.Linq;
using osu.Game.Audio;
namespace osu.Game.Tests.Beatmaps.Formats
{
@ -55,7 +56,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo;
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
Assert.AreEqual(false, beatmapInfo.Countdown);
Assert.AreEqual(SampleSet.Soft, beatmapInfo.SampleSet);
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
Assert.AreEqual(PlayMode.Osu, beatmapInfo.Mode);
@ -137,12 +137,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(slider);
Assert.AreEqual(new Vector2(192, 168), slider.Position);
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;
Assert.IsNotNull(hit);
Assert.AreEqual(new Vector2(304, 56), hit.Position);
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 OpenTK.Graphics;
using osu.Game.Beatmaps.Events;
using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
using osu.Game.Modes;
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
}
private LegacySampleBank defaultSampleBank;
private int defaultSampleVolume = 100;
private readonly int beatmapVersion;
public OsuLegacyDecoder()
@ -73,7 +75,10 @@ namespace osu.Game.Beatmaps.Formats
beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1;
break;
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;
case @"StackLeniency":
beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo);
@ -203,28 +208,56 @@ namespace osu.Game.Beatmaps.Formats
private void handleTimingPoints(Beatmap beatmap, string val)
{
ControlPoint cp = null;
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;
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
cp = new ControlPoint
{
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])
};
int effectFlags = int.Parse(split[7]);
kiaiMode = (effectFlags & 1) > 0;
omitFirstBarSignature = (effectFlags & 8) > 0;
}
if (cp != null)
beatmap.TimingInfo.ControlPoints.Add(cp);
string stringSampleSet = sampleSet.ToString().ToLower();
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)
@ -271,7 +304,7 @@ namespace osu.Game.Beatmaps.Formats
{
beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion;
HitObjectParser parser = null;
HitObjectParser parser = new LegacyHitObjectParser();
Section section = Section.None;
bool hasCustomColours = false;
@ -305,7 +338,6 @@ namespace osu.Game.Beatmaps.Formats
{
case Section.General:
handleGeneral(beatmap, key, val);
parser = new LegacyHitObjectParser();
break;
case Section.Editor:
handleEditor(beatmap, key, val);
@ -326,7 +358,7 @@ namespace osu.Game.Beatmaps.Formats
handleColours(beatmap, key, val, ref hasCustomColours);
break;
case Section.HitObjects:
var obj = parser?.Parse(val);
var obj = parser.Parse(val);
if (obj != null)
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 string SampleBank;
public int SampleVolume;
public TimeSignatures TimeSignature;
public double Time;
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.ShowInterface, true);
Set(OsuConfig.KeyOverlay, false);
//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.LoadSubmittedThread, true).Disabled = true;
Set(OsuConfig.LobbyPlayMode, -1).Disabled = true;
Set(OsuConfig.ShowInterface, true).Disabled = true;
Set(OsuConfig.ShowInterfaceDuringRelax, false).Disabled = true;
Set(OsuConfig.LobbyShowExistingOnly, false).Disabled = true;
Set(OsuConfig.LobbyShowFriendsOnly, false).Disabled = true;

View File

@ -1,7 +1,8 @@
// 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;
using Newtonsoft.Json;
using osu.Game.IO.Serialization;
using osu.Game.Modes;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
@ -10,7 +11,7 @@ using System.Linq;
namespace osu.Game.Database
{
public class BeatmapInfo : IEquatable<BeatmapInfo>
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
@ -47,7 +48,6 @@ namespace osu.Game.Database
// General
public int AudioLeadIn { get; set; }
public bool Countdown { get; set; }
public SampleSet SampleSet { get; set; }
public float StackLeniency { get; set; }
public bool SpecialStyle { get; set; }
public PlayMode Mode { get; set; }
@ -57,17 +57,13 @@ namespace osu.Game.Database
// Editor
// This bookmarks stuff is necessary because DB doesn't know how to store int[]
public string StoredBookmarks { get; internal set; }
[Ignore]
[JsonIgnore]
public int[] Bookmarks
{
get
{
return StoredBookmarks.Split(',').Select(int.Parse).ToArray();
}
set
{
StoredBookmarks = string.Join(",", value);
}
get { return StoredBookmarks.Split(',').Select(int.Parse).ToArray(); }
set { StoredBookmarks = string.Join(",", value); }
}
public double DistanceSpacing { get; set; }
@ -86,7 +82,7 @@ namespace osu.Game.Database
}
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
BeatmapSet.Path == other.BeatmapSet.Path &&
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
BeatmapSet.Path == other.BeatmapSet.Path &&
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
namespace osu.Game.IO.Serialization
{
public interface IJsonSerializable
{
}
public static class JsonSerializableExtensions
{
public static string Serialize(this IJsonSerializable obj)
{
return JsonConvert.SerializeObject(obj);
}
public static T Deserialize<T>(string objString)
{
return JsonConvert.DeserializeObject<T>(objString);
}
public static T DeepClone<T>(this IJsonSerializable obj)
{
return Deserialize<T>(Serialize(obj));
}
}
}

View File

@ -17,10 +17,7 @@ namespace osu.Game.Modes.Judgements
/// </summary>
public double TimeOffset;
/// <summary>
/// The combo after this judgement was processed.
/// </summary>
public int ComboAtHit;
public virtual bool AffectsCombo => true;
/// <summary>
/// The string representation for the result achieved.

View File

@ -7,11 +7,11 @@ using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Judgements;
using Container = osu.Framework.Graphics.Containers.Container;
using osu.Game.Modes.Objects.Types;
using OpenTK.Graphics;
using osu.Game.Audio;
namespace osu.Game.Modes.Objects.Drawables
{
@ -45,15 +45,15 @@ namespace osu.Game.Modes.Objects.Drawables
UpdateState(state);
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]
@ -156,13 +156,16 @@ namespace osu.Game.Modes.Objects.Drawables
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
SampleType type = HitObject.Sample?.Type ?? SampleType.None;
if (type == SampleType.None)
type = SampleType.Normal;
foreach (SampleInfo sample in HitObject.Samples)
{
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;

View File

@ -1,9 +1,10 @@
// 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;
using osu.Game.Audio;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using System.Collections.Generic;
namespace osu.Game.Modes.Objects
{
@ -21,15 +22,31 @@ namespace osu.Game.Modes.Objects
public double StartTime { get; set; }
/// <summary>
/// The sample to be played when this HitObject is hit.
/// The samples to be played when this hit object is hit.
/// </summary>
public HitSampleInfo Sample { get; set; }
public List<SampleInfo> Samples = new List<SampleInfo>();
/// <summary>
/// Applies default values to this HitObject.
/// </summary>
/// <param name="difficulty">The difficulty 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
using OpenTK;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using System.Globalization;
using osu.Game.Modes.Objects.Legacy;
using osu.Game.Beatmaps.Formats;
using osu.Game.Audio;
namespace osu.Game.Modes.Objects
{
@ -20,6 +21,10 @@ namespace osu.Game.Modes.Objects
bool combo = type.HasFlag(LegacyHitObjectType.NewCombo);
type &= ~LegacyHitObjectType.NewCombo;
int sampleVolume = 0;
string normalSampleBank = null;
string addSampleBank = null;
HitObject result;
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])),
NewCombo = combo
};
if (split.Length > 5)
readCustomSampleBanks(split[5], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
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])),
NewCombo = combo
};
if (split.Length > 10)
readCustomSampleBanks(split[10], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
else if ((type & LegacyHitObjectType.Spinner) > 0)
{
@ -91,10 +102,17 @@ namespace osu.Game.Modes.Objects
{
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)
{
// Note: Hold is generated by BMS converts
// Todo: Apparently end time is determined by samples??
// Shouldn't need implementation until mania
result = new LegacyHold
{
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}");
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;
}
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

@ -8,6 +8,7 @@ using osu.Game.Beatmaps;
using osu.Game.Modes.Judgements;
using osu.Game.Modes.Objects;
using osu.Game.Modes.UI;
using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Scoring
{
@ -145,10 +146,21 @@ namespace osu.Game.Modes.Scoring
if (!exists)
{
if (judgement.AffectsCombo)
{
switch (judgement.Result)
{
case HitResult.Miss:
Combo.Value = 0;
break;
case HitResult.Hit:
Combo.Value++;
break;
}
}
Judgements.Add(judgement);
OnNewJudgement(judgement);
judgement.ComboAtHit = Combo.Value;
}
else
OnJudgementChanged(judgement);

View File

@ -9,11 +9,18 @@ using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play;
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
{
public abstract class HudOverlay : Container
{
private const int duration = 100;
private readonly Container content;
public readonly KeyCounterCollection KeyCounter;
public readonly ComboCounter ComboCounter;
public readonly ScoreCounter ScoreCounter;
@ -21,6 +28,9 @@ namespace osu.Game.Modes.UI
public readonly HealthDisplay HealthDisplay;
private Bindable<bool> showKeyCounter;
private Bindable<bool> showHud;
private static bool hasShownNotificationOnce;
protected abstract KeyCounterCollection CreateKeyCounter();
protected abstract ComboCounter CreateComboCounter();
@ -32,28 +42,53 @@ namespace osu.Game.Modes.UI
{
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
Add(content = new Container
{
KeyCounter = CreateKeyCounter(),
ComboCounter = CreateComboCounter(),
ScoreCounter = CreateScoreCounter(),
AccuracyCounter = CreateAccuracyCounter(),
HealthDisplay = CreateHealthDisplay(),
};
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
KeyCounter = CreateKeyCounter(),
ComboCounter = CreateComboCounter(),
ScoreCounter = CreateScoreCounter(),
AccuracyCounter = CreateAccuracyCounter(),
HealthDisplay = CreateHealthDisplay(),
}
});
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
[BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, NotificationManager notificationManager)
{
showKeyCounter = config.GetBindable<bool>(OsuConfig.KeyOverlay);
showKeyCounter.ValueChanged += visibility =>
showKeyCounter.ValueChanged += keyCounterVisibility =>
{
if (visibility)
KeyCounter.Show();
if (keyCounterVisibility)
KeyCounter.FadeIn(duration);
else
KeyCounter.Hide();
KeyCounter.FadeOut(duration);
};
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)
@ -68,5 +103,22 @@ namespace osu.Game.Modes.UI
{
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)
},
new OsuCheckbox
{
LabelText = "Show score overlay",
Bindable = config.GetBindable<bool>(OsuConfig.ShowInterface)
},
new OsuCheckbox
{
LabelText = "Always show key overlay",
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.Audio;
using osu.Game.Graphics.UserInterface;
using OpenTK.Graphics;
namespace osu.Game.Screens.Play.Pause
{
public class QuitButton : DialogButton
public class PauseButton : DialogButton
{
[BackgroundDependencyLoader]
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");
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
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.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Play.Pause;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Graphics.Containers;
using OpenTK.Graphics;
using osu.Framework.Allocation;
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 OnRetry;
public Action OnQuit;
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;
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?";
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.Escape)
{
if (State == Visibility.Hidden) return false;
resume();
OnResume();
return true;
}
@ -94,131 +33,10 @@ namespace osu.Game.Screens.Play
[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 = @"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;
AddButton("Continue", colours.Green, OnResume);
AddButton("Retry", colours.YellowDark, OnRetry);
AddButton("Quit", new Color4(170, 27, 39, 255), OnQuit);
}
}
}

View File

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

View File

@ -71,6 +71,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Audio\SampleInfo.cs" />
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
<Compile Include="Beatmaps\DifficultyCalculator.cs" />
<Compile Include="Beatmaps\IBeatmapCoverter.cs" />
@ -97,6 +98,7 @@
<Compile Include="IO\Legacy\ILegacySerializable.cs" />
<Compile Include="IO\Legacy\SerializationReader.cs" />
<Compile Include="IO\Legacy\SerializationWriter.cs" />
<Compile Include="IO\Serialization\IJsonSerializable.cs" />
<Compile Include="IPC\ScoreIPCChannel.cs" />
<Compile Include="Modes\Replays\Replay.cs" />
<Compile Include="Modes\Judgements\DrawableJudgement.cs" />
@ -148,14 +150,7 @@
<Compile Include="Beatmaps\Drawables\Panel.cs" />
<Compile Include="Modes\Objects\Drawables\DrawableHitObject.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\SampleChange.cs" />
<Compile Include="Beatmaps\Timing\TimingChange.cs" />
<Compile Include="Configuration\OsuConfigManager.cs" />
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
<Compile Include="Overlays\Notifications\Notification.cs" />
@ -198,8 +193,11 @@
<Compile Include="Screens\Multiplayer\Lobby.cs" />
<Compile Include="Screens\Multiplayer\Match.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\PauseOverlay.cs" />
<Compile Include="Screens\Play\Pause\PauseButton.cs" />
<Compile Include="Screens\Play\PlayerInputManager.cs" />
<Compile Include="Screens\Play\PlayerLoader.cs" />
<Compile Include="Screens\Play\ReplayPlayer.cs" />
@ -336,12 +334,8 @@
<Compile Include="Screens\Select\SearchTextBox.cs" />
<Compile Include="Screens\Select\FooterButton.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\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="Modes\Mods\Mod.cs" />
<Compile Include="Overlays\Mods\ModButton.cs" />