mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 00:42:55 +08:00
Merge branch 'master' into userpage
This commit is contained in:
commit
8fa076b5d7
@ -1 +1 @@
|
|||||||
Subproject commit 8baad1b9484b9f35724e2f965c18cfe710907d80
|
Subproject commit 925bbe42bab95078b9d33189205b5b1b76bf8e01
|
@ -1 +1 @@
|
|||||||
Subproject commit 9f46a456dc3a56dcbff09671a3f588b16a464106
|
Subproject commit a5199500cc3ba96101fd858e0f78f36e538697b1
|
39
osu.Desktop.VisualTests/Tests/TestCaseBreadcrumbs.cs
Normal file
39
osu.Desktop.VisualTests/Tests/TestCaseBreadcrumbs.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// 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.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
|
{
|
||||||
|
internal class TestCaseBreadcrumbs : TestCase
|
||||||
|
{
|
||||||
|
public override string Description => @"breadcrumb > control";
|
||||||
|
|
||||||
|
public override void Reset()
|
||||||
|
{
|
||||||
|
base.Reset();
|
||||||
|
|
||||||
|
BreadcrumbControl<BreadcrumbTab> c;
|
||||||
|
Add(c = new BreadcrumbControl<BreadcrumbTab>
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 0.5f,
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep(@"first", () => c.Current.Value = BreadcrumbTab.Click);
|
||||||
|
AddStep(@"second", () => c.Current.Value = BreadcrumbTab.The);
|
||||||
|
AddStep(@"third", () => c.Current.Value = BreadcrumbTab.Circles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum BreadcrumbTab
|
||||||
|
{
|
||||||
|
Click,
|
||||||
|
The,
|
||||||
|
Circles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,9 @@ using OpenTK;
|
|||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Timing;
|
using osu.Game.Rulesets.Mania.Timing;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
@ -59,6 +62,51 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Action createPlayfieldWithNotesAcceptingInput = () =>
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
var rateAdjustClock = new StopwatchClock(true) { Rate = 0.5 };
|
||||||
|
|
||||||
|
ManiaPlayfield playField;
|
||||||
|
Add(playField = new ManiaPlayfield(4, new List<TimingChange> { new TimingChange { BeatLength = 200 } })
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Scale = new Vector2(1, -1),
|
||||||
|
Clock = new FramedClock(rateAdjustClock)
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int t = 1000; t <= 2000; t += 100)
|
||||||
|
{
|
||||||
|
playField.Add(new DrawableNote(new Note
|
||||||
|
{
|
||||||
|
StartTime = t,
|
||||||
|
Column = 0
|
||||||
|
}, new Bindable<Key>(Key.D)));
|
||||||
|
|
||||||
|
playField.Add(new DrawableNote(new Note
|
||||||
|
{
|
||||||
|
StartTime = t,
|
||||||
|
Column = 3
|
||||||
|
}, new Bindable<Key>(Key.K)));
|
||||||
|
}
|
||||||
|
|
||||||
|
playField.Add(new DrawableHoldNote(new HoldNote
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Duration = 1000,
|
||||||
|
Column = 1
|
||||||
|
}, new Bindable<Key>(Key.F)));
|
||||||
|
|
||||||
|
playField.Add(new DrawableHoldNote(new HoldNote
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Duration = 1000,
|
||||||
|
Column = 2
|
||||||
|
}, new Bindable<Key>(Key.J)));
|
||||||
|
};
|
||||||
|
|
||||||
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
||||||
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
||||||
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
||||||
@ -76,11 +124,13 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
AddWaitStep(10);
|
AddWaitStep(10);
|
||||||
AddStep("Right special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Right));
|
AddStep("Right special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Right));
|
||||||
AddWaitStep(10);
|
AddWaitStep(10);
|
||||||
|
|
||||||
|
AddStep("Notes with input", () => createPlayfieldWithNotesAcceptingInput());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerKeyDown(Column column)
|
private void triggerKeyDown(Column column)
|
||||||
{
|
{
|
||||||
column.TriggerKeyDown(new InputState(), new KeyDownEventArgs
|
column.TriggerOnKeyDown(new InputState(), new KeyDownEventArgs
|
||||||
{
|
{
|
||||||
Key = column.Key,
|
Key = column.Key,
|
||||||
Repeat = false
|
Repeat = false
|
||||||
@ -89,7 +139,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
|
|
||||||
private void triggerKeyUp(Column column)
|
private void triggerKeyUp(Column column)
|
||||||
{
|
{
|
||||||
column.TriggerKeyUp(new InputState(), new KeyUpEventArgs
|
column.TriggerOnKeyUp(new InputState(), new KeyUpEventArgs
|
||||||
{
|
{
|
||||||
Key = column.Key
|
Key = column.Key
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
using osu.Game.Screens.Play.ReplaySettings;
|
||||||
|
|
||||||
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
|
{
|
||||||
|
internal class TestCaseReplaySettingsOverlay : TestCase
|
||||||
|
{
|
||||||
|
public override string Description => @"Settings visible in replay/auto";
|
||||||
|
|
||||||
|
private ExampleContainer container;
|
||||||
|
|
||||||
|
public override void Reset()
|
||||||
|
{
|
||||||
|
base.Reset();
|
||||||
|
|
||||||
|
Add(new ReplaySettingsOverlay()
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(container = new ExampleContainer());
|
||||||
|
|
||||||
|
AddStep(@"Add button", () => container.Add(new OsuButton
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Text = @"Button",
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddStep(@"Add checkbox", () => container.Add(new ReplayCheckbox
|
||||||
|
{
|
||||||
|
LabelText = "Checkbox",
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddStep(@"Add textbox", () => container.Add(new FocusedTextBox
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 30,
|
||||||
|
PlaceholderText = "Textbox",
|
||||||
|
HoldFocus = false,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExampleContainer : ReplayGroup
|
||||||
|
{
|
||||||
|
protected override string Title => @"example";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs
Normal file
19
osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// 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.Testing;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
|
{
|
||||||
|
internal class TestCaseSkipButton : TestCase
|
||||||
|
{
|
||||||
|
public override string Description => @"Skip skip skippediskip";
|
||||||
|
|
||||||
|
public override void Reset()
|
||||||
|
{
|
||||||
|
base.Reset();
|
||||||
|
Add(new SkipButton(Clock.CurrentTime + 5000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,92 +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.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using OpenTK;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
|
||||||
{
|
|
||||||
internal class TestCaseTooltip : TestCase
|
|
||||||
{
|
|
||||||
public override string Description => "tests tooltips on various elements";
|
|
||||||
|
|
||||||
public override void Reset()
|
|
||||||
{
|
|
||||||
base.Reset();
|
|
||||||
OsuSliderBar<int> slider;
|
|
||||||
OsuSliderBar<double> sliderDouble;
|
|
||||||
|
|
||||||
const float width = 400;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Spacing = new Vector2(0, 10),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new TooltipTextContainer("text with a tooltip"),
|
|
||||||
new TooltipTextContainer("more text with another tooltip"),
|
|
||||||
new TooltipTextbox
|
|
||||||
{
|
|
||||||
Text = "a textbox with a tooltip",
|
|
||||||
Size = new Vector2(width,30),
|
|
||||||
},
|
|
||||||
slider = new OsuSliderBar<int>
|
|
||||||
{
|
|
||||||
Width = width,
|
|
||||||
},
|
|
||||||
sliderDouble = new OsuSliderBar<double>
|
|
||||||
{
|
|
||||||
Width = width,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
slider.Current.BindTo(new BindableInt(5)
|
|
||||||
{
|
|
||||||
MaxValue = 10,
|
|
||||||
MinValue = 0
|
|
||||||
});
|
|
||||||
|
|
||||||
sliderDouble.Current.BindTo(new BindableDouble(0.5)
|
|
||||||
{
|
|
||||||
MaxValue = 1,
|
|
||||||
MinValue = 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TooltipTextContainer : Container, IHasTooltip
|
|
||||||
{
|
|
||||||
private readonly OsuSpriteText text;
|
|
||||||
|
|
||||||
public string TooltipText => text.Text;
|
|
||||||
|
|
||||||
public TooltipTextContainer(string tooltipText)
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
text = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = tooltipText,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TooltipTextbox : OsuTextBox, IHasTooltip
|
|
||||||
{
|
|
||||||
public string TooltipText => Text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,20 +3,18 @@
|
|||||||
|
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Screens.Play;
|
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
internal class TestCaseTwoLayerButton : TestCase
|
internal class TestCaseTwoLayerButton : TestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Back and skip and what not";
|
public override string Description => @"Mostly back button";
|
||||||
|
|
||||||
public override void Reset()
|
public override void Reset()
|
||||||
{
|
{
|
||||||
base.Reset();
|
base.Reset();
|
||||||
|
|
||||||
Add(new BackButton());
|
Add(new BackButton());
|
||||||
Add(new SkipButton(Clock.CurrentTime + 5000));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,14 +32,14 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
Username = @"flyte",
|
Username = @"flyte",
|
||||||
Id = 3103765,
|
Id = 3103765,
|
||||||
Country = new Country { FlagName = @"JP" },
|
Country = new Country { FlagName = @"JP" },
|
||||||
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/3103765/5b012e13611d5761caa7e24fecb3d3a16e1cf48fc2a3032cfd43dd444af83d82.jpeg"
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
|
||||||
}) { Width = 300 },
|
}) { Width = 300 },
|
||||||
peppy = new UserPanel(new User
|
peppy = new UserPanel(new User
|
||||||
{
|
{
|
||||||
Username = @"peppy",
|
Username = @"peppy",
|
||||||
Id = 2,
|
Id = 2,
|
||||||
Country = new Country { FlagName = @"AU" },
|
Country = new Country { FlagName = @"AU" },
|
||||||
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/2/08cad88747c235a64fca5f1b770e100f120827ded1ffe3b66bfcd19c940afa65.jpeg"
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
|
||||||
}) { Width = 300 },
|
}) { Width = 300 },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -196,6 +196,7 @@
|
|||||||
<Compile Include="Tests\TestCaseMusicController.cs" />
|
<Compile Include="Tests\TestCaseMusicController.cs" />
|
||||||
<Compile Include="Tests\TestCaseNotificationManager.cs" />
|
<Compile Include="Tests\TestCaseNotificationManager.cs" />
|
||||||
<Compile Include="Tests\TestCaseOnScreenDisplay.cs" />
|
<Compile Include="Tests\TestCaseOnScreenDisplay.cs" />
|
||||||
|
<Compile Include="Tests\TestCaseReplaySettingsOverlay.cs" />
|
||||||
<Compile Include="Tests\TestCasePlayer.cs" />
|
<Compile Include="Tests\TestCasePlayer.cs" />
|
||||||
<Compile Include="Tests\TestCaseHitObjects.cs" />
|
<Compile Include="Tests\TestCaseHitObjects.cs" />
|
||||||
<Compile Include="Tests\TestCaseKeyCounter.cs" />
|
<Compile Include="Tests\TestCaseKeyCounter.cs" />
|
||||||
@ -203,12 +204,12 @@
|
|||||||
<Compile Include="Tests\TestCaseReplay.cs" />
|
<Compile Include="Tests\TestCaseReplay.cs" />
|
||||||
<Compile Include="Tests\TestCaseResults.cs" />
|
<Compile Include="Tests\TestCaseResults.cs" />
|
||||||
<Compile Include="Tests\TestCaseScoreCounter.cs" />
|
<Compile Include="Tests\TestCaseScoreCounter.cs" />
|
||||||
|
<Compile Include="Tests\TestCaseSkipButton.cs" />
|
||||||
<Compile Include="Tests\TestCaseTabControl.cs" />
|
<Compile Include="Tests\TestCaseTabControl.cs" />
|
||||||
<Compile Include="Tests\TestCaseTaikoHitObjects.cs" />
|
<Compile Include="Tests\TestCaseTaikoHitObjects.cs" />
|
||||||
<Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
|
<Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
|
||||||
<Compile Include="Tests\TestCaseTextAwesome.cs" />
|
<Compile Include="Tests\TestCaseTextAwesome.cs" />
|
||||||
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
|
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
|
||||||
<Compile Include="Tests\TestCaseTooltip.cs" />
|
|
||||||
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />
|
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />
|
||||||
<Compile Include="Tests\TestCaseUserProfile.cs" />
|
<Compile Include="Tests\TestCaseUserProfile.cs" />
|
||||||
<Compile Include="VisualTestGame.cs" />
|
<Compile Include="VisualTestGame.cs" />
|
||||||
@ -224,6 +225,7 @@
|
|||||||
<Compile Include="Tests\TestCaseDrawableRoom.cs" />
|
<Compile Include="Tests\TestCaseDrawableRoom.cs" />
|
||||||
<Compile Include="Tests\TestCaseUserPanel.cs" />
|
<Compile Include="Tests\TestCaseUserPanel.cs" />
|
||||||
<Compile Include="Tests\TestCaseDirect.cs" />
|
<Compile Include="Tests\TestCaseDirect.cs" />
|
||||||
|
<Compile Include="Tests\TestCaseBreadcrumbs.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
|
@ -28,7 +28,14 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
{
|
{
|
||||||
new CatchModEasy(),
|
new CatchModEasy(),
|
||||||
new CatchModNoFail(),
|
new CatchModNoFail(),
|
||||||
|
new MultiMod
|
||||||
|
{
|
||||||
|
Mods = new Mod[]
|
||||||
|
{
|
||||||
new CatchModHalfTime(),
|
new CatchModHalfTime(),
|
||||||
|
new CatchModDaycore(),
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.DifficultyIncrease:
|
case ModType.DifficultyIncrease:
|
||||||
|
@ -32,6 +32,11 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CatchModDaycore : ModDaycore
|
||||||
|
{
|
||||||
|
public override double ScoreMultiplier => 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
public class CatchModDoubleTime : ModDoubleTime
|
public class CatchModDoubleTime : ModDoubleTime
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => 1.06;
|
||||||
|
@ -13,6 +13,7 @@ using osu.Game.Rulesets.Mania.MathUtils;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
|
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Beatmaps
|
namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||||
{
|
{
|
||||||
@ -161,9 +162,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
pattern.Add(new HoldNote
|
pattern.Add(new HoldNote
|
||||||
{
|
{
|
||||||
StartTime = HitObject.StartTime,
|
StartTime = HitObject.StartTime,
|
||||||
Samples = HitObject.Samples,
|
|
||||||
Duration = endTimeData.Duration,
|
Duration = endTimeData.Duration,
|
||||||
Column = column,
|
Column = column,
|
||||||
|
Head = { Samples = sampleInfoListAt(HitObject.StartTime) },
|
||||||
|
Tail = { Samples = sampleInfoListAt(endTimeData.EndTime) },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (positionData != null)
|
else if (positionData != null)
|
||||||
@ -178,6 +180,24 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the sample info list at a point in time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="time">The time to retrieve the sample info list from.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private SampleInfoList sampleInfoListAt(double time)
|
||||||
|
{
|
||||||
|
var curveData = HitObject as IHasCurve;
|
||||||
|
|
||||||
|
if (curveData == null)
|
||||||
|
return HitObject.Samples;
|
||||||
|
|
||||||
|
double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.RepeatCount;
|
||||||
|
|
||||||
|
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||||
|
return curveData.RepeatSamples[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,14 +471,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newObject = new HoldNote
|
var holdNote = new HoldNote
|
||||||
{
|
{
|
||||||
StartTime = startTime,
|
StartTime = startTime,
|
||||||
Samples = sampleInfoListAt(startTime),
|
|
||||||
EndSamples = sampleInfoListAt(endTime),
|
|
||||||
Column = column,
|
Column = column,
|
||||||
Duration = endTime - startTime
|
Duration = endTime - startTime,
|
||||||
|
Head = { Samples = sampleInfoListAt(startTime) },
|
||||||
|
Tail = { Samples = sampleInfoListAt(endTime) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
newObject = holdNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern.Add(newObject);
|
pattern.Add(newObject);
|
||||||
|
@ -69,18 +69,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
if (holdNote)
|
if (holdNote)
|
||||||
{
|
{
|
||||||
newObject = new HoldNote
|
var hold = new HoldNote
|
||||||
{
|
{
|
||||||
StartTime = HitObject.StartTime,
|
StartTime = HitObject.StartTime,
|
||||||
EndSamples = HitObject.Samples,
|
|
||||||
Column = column,
|
Column = column,
|
||||||
Duration = endTime - HitObject.StartTime
|
Duration = endTime - HitObject.StartTime
|
||||||
};
|
};
|
||||||
|
|
||||||
newObject.Samples.Add(new SampleInfo
|
hold.Head.Samples.Add(new SampleInfo
|
||||||
{
|
{
|
||||||
Name = SampleInfo.HIT_NORMAL
|
Name = SampleInfo.HIT_NORMAL
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hold.Tail.Samples = HitObject.Samples;
|
||||||
|
|
||||||
|
newObject = hold;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
37
osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs
Normal file
37
osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs
Normal 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
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
|
{
|
||||||
|
public class HoldNoteTailJudgement : ManiaJudgement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the hold note has been released too early and shouldn't give full score for the release.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasBroken;
|
||||||
|
|
||||||
|
public override int NumericResultForScore(ManiaHitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return base.NumericResultForScore(result);
|
||||||
|
case ManiaHitResult.Great:
|
||||||
|
case ManiaHitResult.Perfect:
|
||||||
|
return base.NumericResultForScore(HasBroken ? ManiaHitResult.Good : result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int NumericResultForAccuracy(ManiaHitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return base.NumericResultForAccuracy(result);
|
||||||
|
case ManiaHitResult.Great:
|
||||||
|
case ManiaHitResult.Perfect:
|
||||||
|
return base.NumericResultForAccuracy(HasBroken ? ManiaHitResult.Good : result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
Normal file
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
Normal file
@ -0,0 +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
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
|
{
|
||||||
|
public class HoldNoteTickJudgement : ManiaJudgement
|
||||||
|
{
|
||||||
|
public override bool AffectsCombo => false;
|
||||||
|
|
||||||
|
public override int NumericResultForScore(ManiaHitResult result) => 20;
|
||||||
|
public override int NumericResultForAccuracy(ManiaHitResult result) => 0; // Don't count ticks into accuracy
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,37 @@
|
|||||||
// 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.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Judgements
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
{
|
{
|
||||||
public class ManiaJudgement : Judgement
|
public class ManiaJudgement : Judgement
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum possible hit result.
|
||||||
|
/// </summary>
|
||||||
|
public const ManiaHitResult MAX_HIT_RESULT = ManiaHitResult.Perfect;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The result value for the combo portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(ManiaResult);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The result value for the accuracy portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(ManiaResult);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum result value for the combo portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum result value for the accuracy portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
|
||||||
|
|
||||||
public override string ResultString => string.Empty;
|
public override string ResultString => string.Empty;
|
||||||
|
|
||||||
public override string MaxResultString => string.Empty;
|
public override string MaxResultString => string.Empty;
|
||||||
@ -15,5 +41,42 @@ namespace osu.Game.Rulesets.Mania.Judgements
|
|||||||
/// The hit result.
|
/// The hit result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ManiaHitResult ManiaResult;
|
public ManiaHitResult ManiaResult;
|
||||||
|
|
||||||
|
public virtual int NumericResultForScore(ManiaHitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
case ManiaHitResult.Bad:
|
||||||
|
return 50;
|
||||||
|
case ManiaHitResult.Ok:
|
||||||
|
return 100;
|
||||||
|
case ManiaHitResult.Good:
|
||||||
|
return 200;
|
||||||
|
case ManiaHitResult.Great:
|
||||||
|
case ManiaHitResult.Perfect:
|
||||||
|
return 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual int NumericResultForAccuracy(ManiaHitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
case ManiaHitResult.Bad:
|
||||||
|
return 50;
|
||||||
|
case ManiaHitResult.Ok:
|
||||||
|
return 100;
|
||||||
|
case ManiaHitResult.Good:
|
||||||
|
return 200;
|
||||||
|
case ManiaHitResult.Great:
|
||||||
|
return 300;
|
||||||
|
case ManiaHitResult.Perfect:
|
||||||
|
return 305;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,14 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
{
|
{
|
||||||
new ManiaModEasy(),
|
new ManiaModEasy(),
|
||||||
new ManiaModNoFail(),
|
new ManiaModNoFail(),
|
||||||
|
new MultiMod
|
||||||
|
{
|
||||||
|
Mods = new Mod[]
|
||||||
|
{
|
||||||
new ManiaModHalfTime(),
|
new ManiaModHalfTime(),
|
||||||
|
new ManiaModDaycore(),
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.DifficultyIncrease:
|
case ModType.DifficultyIncrease:
|
||||||
|
@ -34,6 +34,11 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ManiaModDaycore : ModDaycore
|
||||||
|
{
|
||||||
|
public override double ScoreMultiplier => 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
public class ManiaModDoubleTime : ModDoubleTime
|
public class ManiaModDoubleTime : ModDoubleTime
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.0;
|
public override double ScoreMultiplier => 1.0;
|
||||||
|
21
osu.Game.Rulesets.Mania/Objects/BarLine.cs
Normal file
21
osu.Game.Rulesets.Mania/Objects/BarLine.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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.ControlPoints;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
|
{
|
||||||
|
public class BarLine : ManiaHitObject
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The control point which this bar line is part of.
|
||||||
|
/// </summary>
|
||||||
|
public TimingControlPoint ControlPoint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The index of the beat which this bar line represents within the control point.
|
||||||
|
/// This is a "major" bar line if <see cref="BeatIndex"/> % <see cref="TimingControlPoint.TimeSignature"/> == 0.
|
||||||
|
/// </summary>
|
||||||
|
public int BeatIndex;
|
||||||
|
}
|
||||||
|
}
|
74
osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
Normal file
74
osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using OpenTK;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualises a <see cref="BarLine"/>. Although this derives DrawableManiaHitObject,
|
||||||
|
/// this does not handle input/sound like a normal hit object.
|
||||||
|
/// </summary>
|
||||||
|
public class DrawableBarLine : DrawableManiaHitObject<BarLine>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Height of major bar line triangles.
|
||||||
|
/// </summary>
|
||||||
|
private const float triangle_height = 12;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offset of the major bar line triangles from the sides of the bar line.
|
||||||
|
/// </summary>
|
||||||
|
private const float triangle_offset = 9;
|
||||||
|
|
||||||
|
public DrawableBarLine(BarLine barLine)
|
||||||
|
: base(barLine)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = 1;
|
||||||
|
|
||||||
|
Add(new Box
|
||||||
|
{
|
||||||
|
Name = "Bar line",
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
});
|
||||||
|
|
||||||
|
bool isMajor = barLine.BeatIndex % (int)barLine.ControlPoint.TimeSignature == 0;
|
||||||
|
|
||||||
|
if (isMajor)
|
||||||
|
{
|
||||||
|
Add(new EquilateralTriangle
|
||||||
|
{
|
||||||
|
Name = "Left triangle",
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Size = new Vector2(triangle_height),
|
||||||
|
X = -triangle_offset,
|
||||||
|
Rotation = 90
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(new EquilateralTriangle
|
||||||
|
{
|
||||||
|
Name = "Right triangle",
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Size = new Vector2(triangle_height),
|
||||||
|
X = triangle_offset,
|
||||||
|
Rotation = -90
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMajor && barLine.BeatIndex % 2 == 1)
|
||||||
|
Alpha = 0.2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,14 +7,34 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using OpenTK;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualises a <see cref="HoldNote"/> hit object.
|
||||||
|
/// </summary>
|
||||||
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>
|
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>
|
||||||
{
|
{
|
||||||
private readonly NotePiece headPiece;
|
private readonly DrawableNote head;
|
||||||
|
private readonly DrawableNote tail;
|
||||||
|
|
||||||
private readonly BodyPiece bodyPiece;
|
private readonly BodyPiece bodyPiece;
|
||||||
private readonly NotePiece tailPiece;
|
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
|
||||||
|
/// </summary>
|
||||||
|
private double? holdStartTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the hold note has been released too early and shouldn't give full score for the release.
|
||||||
|
/// </summary>
|
||||||
|
private bool hasBroken;
|
||||||
|
|
||||||
public DrawableHoldNote(HoldNote hitObject, Bindable<Key> key = null)
|
public DrawableHoldNote(HoldNote hitObject, Bindable<Key> key = null)
|
||||||
: base(hitObject, key)
|
: base(hitObject, key)
|
||||||
@ -32,17 +52,39 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
},
|
},
|
||||||
headPiece = new NotePiece
|
tickContainer = new Container<DrawableHoldNoteTick>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RelativeCoordinateSpace = new Vector2(1, (float)HitObject.Duration)
|
||||||
|
},
|
||||||
|
head = new DrawableHeadNote(this, key)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
tailPiece = new NotePiece
|
tail = new DrawableTailNote(this, key)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
foreach (var tick in HitObject.Ticks)
|
||||||
|
{
|
||||||
|
var drawableTick = new DrawableHoldNoteTick(tick)
|
||||||
|
{
|
||||||
|
HoldStartTime = () => holdStartTime
|
||||||
|
};
|
||||||
|
|
||||||
|
// To make the ticks relative to ourselves we need to offset them backwards
|
||||||
|
drawableTick.Y -= (float)HitObject.StartTime;
|
||||||
|
|
||||||
|
tickContainer.Add(drawableTick);
|
||||||
|
AddNested(drawableTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddNested(head);
|
||||||
|
AddNested(tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Color4 AccentColour
|
public override Color4 AccentColour
|
||||||
@ -54,9 +96,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return;
|
return;
|
||||||
base.AccentColour = value;
|
base.AccentColour = value;
|
||||||
|
|
||||||
headPiece.AccentColour = value;
|
tickContainer.Children.ForEach(t => t.AccentColour = value);
|
||||||
|
|
||||||
bodyPiece.AccentColour = value;
|
bodyPiece.AccentColour = value;
|
||||||
tailPiece.AccentColour = value;
|
head.AccentColour = value;
|
||||||
|
tail.AccentColour = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,14 +108,132 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (Time.Current > HitObject.StartTime)
|
// Make sure the keypress happened within the body of the hold note
|
||||||
headPiece.Colour = Color4.Green;
|
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
|
||||||
if (Time.Current > HitObject.EndTime)
|
return false;
|
||||||
|
|
||||||
|
if (args.Key != Key)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (args.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
||||||
|
// and within the limited range of the above if-statement. This state will be managed by the head note if the
|
||||||
|
// user has pressed during the hit windows of the head note.
|
||||||
|
holdStartTime = Time.Current;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
||||||
{
|
{
|
||||||
bodyPiece.Colour = Color4.Green;
|
// Make sure that the user started holding the key during the hold note
|
||||||
tailPiece.Colour = Color4.Green;
|
if (!holdStartTime.HasValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (args.Key != Key)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
holdStartTime = null;
|
||||||
|
|
||||||
|
// If the key has been released too early, the user should not receive full score for the release
|
||||||
|
if (!tail.Judged)
|
||||||
|
hasBroken = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The head note of a hold.
|
||||||
|
/// </summary>
|
||||||
|
private class DrawableHeadNote : DrawableNote
|
||||||
|
{
|
||||||
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
|
public DrawableHeadNote(DrawableHoldNote holdNote, Bindable<Key> key = null)
|
||||||
|
: base(holdNote.HitObject.Head, key)
|
||||||
|
{
|
||||||
|
this.holdNote = holdNote;
|
||||||
|
|
||||||
|
RelativePositionAxes = Axes.None;
|
||||||
|
Y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
if (!base.OnKeyDown(state, args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We only want to trigger a holding state from the head if the head has received a judgement
|
||||||
|
if (!Judged)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If the key has been released too early, the user should not receive full score for the release
|
||||||
|
if (Judgement.Result == HitResult.Miss)
|
||||||
|
holdNote.hasBroken = true;
|
||||||
|
|
||||||
|
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
|
||||||
|
// The body doesn't handle these early early hits, so we have to explicitly set the holding state here
|
||||||
|
holdNote.holdStartTime = Time.Current;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tail note of a hold.
|
||||||
|
/// </summary>
|
||||||
|
private class DrawableTailNote : DrawableNote
|
||||||
|
{
|
||||||
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
|
public DrawableTailNote(DrawableHoldNote holdNote, Bindable<Key> key = null)
|
||||||
|
: base(holdNote.HitObject.Tail, key)
|
||||||
|
{
|
||||||
|
this.holdNote = holdNote;
|
||||||
|
|
||||||
|
RelativePositionAxes = Axes.None;
|
||||||
|
Y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ManiaJudgement CreateJudgement() => new HoldNoteTailJudgement();
|
||||||
|
|
||||||
|
protected override void CheckJudgement(bool userTriggered)
|
||||||
|
{
|
||||||
|
base.CheckJudgement(userTriggered);
|
||||||
|
|
||||||
|
var tailJudgement = Judgement as HoldNoteTailJudgement;
|
||||||
|
if (tailJudgement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tailJudgement.HasBroken = holdNote.hasBroken;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
||||||
|
{
|
||||||
|
// Make sure that the user started holding the key during the hold note
|
||||||
|
if (!holdNote.holdStartTime.HasValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Judgement.Result != HitResult.None)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (args.Key != Key)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UpdateJudgement(true);
|
||||||
|
|
||||||
|
// Handled by the hold note, which will set holding = false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
// Tail doesn't handle key down
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
// 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 OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualises a <see cref="HoldNoteTick"/> hit object.
|
||||||
|
/// </summary>
|
||||||
|
public class DrawableHoldNoteTick : DrawableManiaHitObject<HoldNoteTick>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// References the time at which the user started holding the hold note.
|
||||||
|
/// </summary>
|
||||||
|
public Func<double?> HoldStartTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// References whether the user is currently holding the hold note.
|
||||||
|
/// </summary>
|
||||||
|
public Func<bool> IsHolding;
|
||||||
|
|
||||||
|
private readonly Container glowContainer;
|
||||||
|
|
||||||
|
public DrawableHoldNoteTick(HoldNoteTick hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre;
|
||||||
|
Origin = Anchor.TopCentre;
|
||||||
|
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Size = new Vector2(1);
|
||||||
|
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
glowContainer = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the default glow
|
||||||
|
AccentColour = Color4.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Color4 AccentColour
|
||||||
|
{
|
||||||
|
get { return base.AccentColour; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.AccentColour = value;
|
||||||
|
|
||||||
|
glowContainer.EdgeEffect = new EdgeEffect
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Radius = 2f,
|
||||||
|
Roundness = 15f,
|
||||||
|
Colour = value.Opacity(0.3f)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ManiaJudgement CreateJudgement() => new HoldNoteTickJudgement();
|
||||||
|
|
||||||
|
protected override void CheckJudgement(bool userTriggered)
|
||||||
|
{
|
||||||
|
if (!userTriggered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Time.Current < HitObject.StartTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HoldStartTime?.Invoke() > HitObject.StartTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Judgement.ManiaResult = ManiaHitResult.Perfect;
|
||||||
|
Judgement.Result = HitResult.Hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(ArmedState state)
|
||||||
|
{
|
||||||
|
switch (State)
|
||||||
|
{
|
||||||
|
case ArmedState.Hit:
|
||||||
|
AccentColour = Color4.Green;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
if (Judgement.Result != HitResult.None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsHolding?.Invoke() != true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdateJudgement(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,9 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualises a <see cref="Note"/> hit object.
|
||||||
|
/// </summary>
|
||||||
public class DrawableNote : DrawableManiaHitObject<Note>
|
public class DrawableNote : DrawableManiaHitObject<Note>
|
||||||
{
|
{
|
||||||
private readonly NotePiece headPiece;
|
private readonly NotePiece headPiece;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
// 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.Audio;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
@ -12,7 +11,86 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a hit object which requires pressing, holding, and releasing a key.
|
/// Represents a hit object which requires pressing, holding, and releasing a key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HoldNote : Note, IHasEndTime
|
public class HoldNote : ManiaHitObject, IHasEndTime
|
||||||
|
{
|
||||||
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
|
private double duration;
|
||||||
|
public double Duration
|
||||||
|
{
|
||||||
|
get { return duration; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
duration = value;
|
||||||
|
Tail.StartTime = EndTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double StartTime
|
||||||
|
{
|
||||||
|
get { return base.StartTime; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.StartTime = value;
|
||||||
|
Head.StartTime = value;
|
||||||
|
Tail.StartTime = EndTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The head note of the hold.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Note Head = new Note();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tail note of the hold.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Note Tail = new TailNote();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time between ticks of this hold.
|
||||||
|
/// </summary>
|
||||||
|
private double tickSpacing = 50;
|
||||||
|
|
||||||
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate;
|
||||||
|
|
||||||
|
Head.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
Tail.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The scoring scoring ticks of the hold note.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<HoldNoteTick> Ticks => ticks ?? (ticks = createTicks());
|
||||||
|
private List<HoldNoteTick> ticks;
|
||||||
|
|
||||||
|
private List<HoldNoteTick> createTicks()
|
||||||
|
{
|
||||||
|
var ret = new List<HoldNoteTick>();
|
||||||
|
|
||||||
|
if (tickSpacing == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing)
|
||||||
|
{
|
||||||
|
ret.Add(new HoldNoteTick
|
||||||
|
{
|
||||||
|
StartTime = t
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tail of the hold note.
|
||||||
|
/// </summary>
|
||||||
|
private class TailNote : Note
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lenience of release hit windows. This is to make cases where the hold note release
|
/// Lenience of release hit windows. This is to make cases where the hold note release
|
||||||
@ -20,24 +98,12 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const double release_window_lenience = 1.5;
|
private const double release_window_lenience = 1.5;
|
||||||
|
|
||||||
public double Duration { get; set; }
|
|
||||||
public double EndTime => StartTime + Duration;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The samples to be played when this hold note is released.
|
|
||||||
/// </summary>
|
|
||||||
public SampleInfoList EndSamples = new SampleInfoList();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The key-release hit windows for this hold note.
|
|
||||||
/// </summary>
|
|
||||||
public HitWindows ReleaseHitWindows { get; protected set; } = new HitWindows();
|
|
||||||
|
|
||||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
ReleaseHitWindows = HitWindows * release_window_lenience;
|
HitWindows *= release_window_lenience;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
Normal file
12
osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// 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.Rulesets.Mania.Objects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A scoring tick of a hold note.
|
||||||
|
/// </summary>
|
||||||
|
public class HoldNoteTick : ManiaHitObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +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 System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
@ -10,6 +15,143 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
{
|
{
|
||||||
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject, ManiaJudgement>
|
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject, ManiaJudgement>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum score achievable.
|
||||||
|
/// Does _not_ include bonus score - for bonus score see <see cref="bonusScore"/>.
|
||||||
|
/// </summary>
|
||||||
|
private const int max_score = 1000000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of the score attributed to combo.
|
||||||
|
/// </summary>
|
||||||
|
private const double combo_portion_max = max_score * 0.2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of the score attributed to accuracy.
|
||||||
|
/// </summary>
|
||||||
|
private const double accuracy_portion_max = max_score * 0.8;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The factor used to determine relevance of combos.
|
||||||
|
/// </summary>
|
||||||
|
private const double combo_base = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The combo value at which hit objects result in the max score possible.
|
||||||
|
/// </summary>
|
||||||
|
private const int combo_relevance_cap = 400;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hit HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_min = 0.75;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hit HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_mid = 0.85;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hit HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_max = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default BAD hit HP increase.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_increase_bad = 0.005;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default OK hit HP increase.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_increase_ok = 0.010;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default GOOD hit HP increase.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_increase_good = 0.035;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default tick hit HP increase.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_increase_tick = 0.040;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default GREAT hit HP increase.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_increase_great = 0.055;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default PERFECT hit HP increase.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_increase_perfect = 0.065;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_miss_min = 0.5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier at OD = 5.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_miss_mid = 0.75;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier at OD = 10.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_miss_max = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default MISS HP increase.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_increase_miss = -0.125;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier. This is multiplied to the miss hp increase.
|
||||||
|
/// </summary>
|
||||||
|
private double hpMissMultiplier = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The HIT HP multiplier. This is multiplied to hit hp increases.
|
||||||
|
/// </summary>
|
||||||
|
private double hpMultiplier = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The cumulative combo portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
private double comboScore => combo_portion_max * comboPortion / maxComboPortion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The cumulative accuracy portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
private double accuracyScore => accuracy_portion_max * Math.Pow(Accuracy, 4) * totalHits / maxTotalHits;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The cumulative bonus score.
|
||||||
|
/// This is added on top of <see cref="max_score"/>, thus the total score can exceed <see cref="max_score"/>.
|
||||||
|
/// </summary>
|
||||||
|
private double bonusScore;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="comboPortion"/> achieved by a perfect playthrough.
|
||||||
|
/// </summary>
|
||||||
|
private double maxComboPortion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The portion of the score dedicated to combo.
|
||||||
|
/// </summary>
|
||||||
|
private double comboPortion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="totalHits"/> achieved by a perfect playthrough.
|
||||||
|
/// </summary>
|
||||||
|
private int maxTotalHits;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total hits.
|
||||||
|
/// </summary>
|
||||||
|
private int totalHits;
|
||||||
|
|
||||||
public ManiaScoreProcessor()
|
public ManiaScoreProcessor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -19,8 +161,124 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ComputeTargets(Beatmap<ManiaHitObject> beatmap)
|
||||||
|
{
|
||||||
|
BeatmapDifficulty difficulty = beatmap.BeatmapInfo.Difficulty;
|
||||||
|
hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max);
|
||||||
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
foreach (var obj in beatmap.HitObjects)
|
||||||
|
{
|
||||||
|
var holdNote = obj as HoldNote;
|
||||||
|
|
||||||
|
if (obj is Note)
|
||||||
|
{
|
||||||
|
AddJudgement(new ManiaJudgement
|
||||||
|
{
|
||||||
|
Result = HitResult.Hit,
|
||||||
|
ManiaResult = ManiaHitResult.Perfect
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (holdNote != null)
|
||||||
|
{
|
||||||
|
// Head
|
||||||
|
AddJudgement(new ManiaJudgement
|
||||||
|
{
|
||||||
|
Result = HitResult.Hit,
|
||||||
|
ManiaResult = ManiaJudgement.MAX_HIT_RESULT
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ticks
|
||||||
|
int tickCount = holdNote.Ticks.Count();
|
||||||
|
for (int i = 0; i < tickCount; i++)
|
||||||
|
{
|
||||||
|
AddJudgement(new HoldNoteTickJudgement
|
||||||
|
{
|
||||||
|
Result = HitResult.Hit,
|
||||||
|
ManiaResult = ManiaJudgement.MAX_HIT_RESULT,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
AddJudgement(new HoldNoteTailJudgement
|
||||||
|
{
|
||||||
|
Result = HitResult.Hit,
|
||||||
|
ManiaResult = ManiaJudgement.MAX_HIT_RESULT
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HasFailed)
|
||||||
|
break;
|
||||||
|
|
||||||
|
hpMultiplier *= 1.01;
|
||||||
|
hpMissMultiplier *= 0.98;
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
maxTotalHits = totalHits;
|
||||||
|
maxComboPortion = comboPortion;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnNewJudgement(ManiaJudgement judgement)
|
protected override void OnNewJudgement(ManiaJudgement judgement)
|
||||||
{
|
{
|
||||||
|
bool isTick = judgement is HoldNoteTickJudgement;
|
||||||
|
|
||||||
|
if (!isTick)
|
||||||
|
totalHits++;
|
||||||
|
|
||||||
|
switch (judgement.Result)
|
||||||
|
{
|
||||||
|
case HitResult.Miss:
|
||||||
|
Health.Value += hpMissMultiplier * hp_increase_miss;
|
||||||
|
break;
|
||||||
|
case HitResult.Hit:
|
||||||
|
if (isTick)
|
||||||
|
{
|
||||||
|
Health.Value += hpMultiplier * hp_increase_tick;
|
||||||
|
bonusScore += judgement.ResultValueForScore;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (judgement.ManiaResult)
|
||||||
|
{
|
||||||
|
case ManiaHitResult.Bad:
|
||||||
|
Health.Value += hpMultiplier * hp_increase_bad;
|
||||||
|
break;
|
||||||
|
case ManiaHitResult.Ok:
|
||||||
|
Health.Value += hpMultiplier * hp_increase_ok;
|
||||||
|
break;
|
||||||
|
case ManiaHitResult.Good:
|
||||||
|
Health.Value += hpMultiplier * hp_increase_good;
|
||||||
|
break;
|
||||||
|
case ManiaHitResult.Great:
|
||||||
|
Health.Value += hpMultiplier * hp_increase_great;
|
||||||
|
break;
|
||||||
|
case ManiaHitResult.Perfect:
|
||||||
|
Health.Value += hpMultiplier * hp_increase_perfect;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A factor that is applied to make higher combos more relevant
|
||||||
|
double comboRelevance = Math.Min(Math.Max(0.5, Math.Log(Combo.Value, combo_base)), Math.Log(combo_relevance_cap, combo_base));
|
||||||
|
comboPortion += judgement.ResultValueForScore * comboRelevance;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scoreForAccuracy = 0;
|
||||||
|
int maxScoreForAccuracy = 0;
|
||||||
|
|
||||||
|
foreach (var j in Judgements)
|
||||||
|
{
|
||||||
|
scoreForAccuracy += j.ResultValueForAccuracy;
|
||||||
|
maxScoreForAccuracy += j.MaxResultValueForAccuracy;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;
|
||||||
|
TotalScore.Value = comboScore + accuracyScore + bonusScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Reset()
|
protected override void Reset()
|
||||||
@ -28,6 +286,10 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
base.Reset();
|
base.Reset();
|
||||||
|
|
||||||
Health.Value = 1;
|
Health.Value = 1;
|
||||||
|
|
||||||
|
bonusScore = 0;
|
||||||
|
comboPortion = 0;
|
||||||
|
totalHits = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Timing
|
namespace osu.Game.Rulesets.Mania.Timing
|
||||||
{
|
{
|
||||||
@ -128,6 +129,8 @@ namespace osu.Game.Rulesets.Mania.Timing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class AutoTimeRelativeContainer : Container
|
private class AutoTimeRelativeContainer : Container
|
||||||
{
|
{
|
||||||
|
protected override IComparer<Drawable> DepthComparer => new HitObjectReverseStartTimeComparer();
|
||||||
|
|
||||||
public override void InvalidateFromChild(Invalidation invalidation)
|
public override void InvalidateFromChild(Invalidation invalidation)
|
||||||
{
|
{
|
||||||
// We only want to re-compute our size when a child's size or position has changed
|
// We only want to re-compute our size when a child's size or position has changed
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// 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 OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
@ -188,7 +187,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject) => ControlPointContainer.Add(hitObject);
|
public void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject)
|
||||||
|
{
|
||||||
|
hitObject.AccentColour = AccentColour;
|
||||||
|
ControlPointContainer.Add(hitObject);
|
||||||
|
}
|
||||||
|
|
||||||
private bool onKeyDown(InputState state, KeyDownEventArgs args)
|
private bool onKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
|
@ -6,9 +6,11 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Lists;
|
using osu.Framework.Lists;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Beatmaps;
|
using osu.Game.Rulesets.Beatmaps;
|
||||||
@ -85,6 +87,34 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
var maniaPlayfield = (ManiaPlayfield)Playfield;
|
||||||
|
|
||||||
|
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
||||||
|
|
||||||
|
SortedList<TimingControlPoint> timingPoints = Beatmap.ControlPointInfo.TimingPoints;
|
||||||
|
for (int i = 0; i < timingPoints.Count; i++)
|
||||||
|
{
|
||||||
|
TimingControlPoint point = timingPoints[i];
|
||||||
|
|
||||||
|
// Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object
|
||||||
|
double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - point.BeatLength : lastObjectTime + point.BeatLength * (int)point.TimeSignature;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
|
||||||
|
{
|
||||||
|
maniaPlayfield.Add(new DrawableBarLine(new BarLine
|
||||||
|
{
|
||||||
|
StartTime = t,
|
||||||
|
ControlPoint = point,
|
||||||
|
BeatIndex = index
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
||||||
|
|
||||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
|
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
|
||||||
|
@ -21,6 +21,7 @@ using osu.Game.Rulesets.Mania.Timing;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Graphics.Transforms;
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
@ -57,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
private readonly FlowContainer<Column> columns;
|
private readonly FlowContainer<Column> columns;
|
||||||
public IEnumerable<Column> Columns => columns.Children;
|
public IEnumerable<Column> Columns => columns.Children;
|
||||||
|
|
||||||
private readonly ControlPointContainer barlineContainer;
|
private readonly ControlPointContainer barLineContainer;
|
||||||
|
|
||||||
private List<Color4> normalColumnColours = new List<Color4>();
|
private List<Color4> normalColumnColours = new List<Color4>();
|
||||||
private Color4 specialColumnColour;
|
private Color4 specialColumnColour;
|
||||||
@ -75,6 +76,15 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = "Masked elements",
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
@ -95,17 +105,24 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Padding = new MarginPadding { Left = 1, Right = 1 },
|
Padding = new MarginPadding { Left = 1, Right = 1 },
|
||||||
Spacing = new Vector2(1, 0)
|
Spacing = new Vector2(1, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Top = HIT_TARGET_POSITION },
|
Padding = new MarginPadding { Top = HIT_TARGET_POSITION },
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
barlineContainer = new ControlPointContainer(timingChanges)
|
barLineContainer = new ControlPointContainer(timingChanges)
|
||||||
{
|
{
|
||||||
Name = "Bar lines",
|
Name = "Bar lines",
|
||||||
RelativeSizeAxes = Axes.Both,
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Y
|
||||||
|
// Width is set in the Update method
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,6 +207,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> h) => Columns.ElementAt(h.HitObject.Column).Add(h);
|
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> h) => Columns.ElementAt(h.HitObject.Column).Add(h);
|
||||||
|
public void Add(DrawableBarLine barline) => barLineContainer.Add(barline);
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
@ -224,7 +242,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
timeSpan = MathHelper.Clamp(timeSpan, time_span_min, time_span_max);
|
timeSpan = MathHelper.Clamp(timeSpan, time_span_min, time_span_max);
|
||||||
|
|
||||||
barlineContainer.TimeSpan = value;
|
barLineContainer.TimeSpan = value;
|
||||||
Columns.ForEach(c => c.ControlPointContainer.TimeSpan = value);
|
Columns.ForEach(c => c.ControlPointContainer.TimeSpan = value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,6 +252,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
TransformTo(() => TimeSpan, newTimeSpan, duration, easing, new TransformTimeSpan());
|
TransformTo(() => TimeSpan, newTimeSpan, duration, easing, new TransformTimeSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
// Due to masking differences, it is not possible to get the width of the columns container automatically
|
||||||
|
// While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually
|
||||||
|
barLineContainer.Width = columns.Width;
|
||||||
|
}
|
||||||
|
|
||||||
private class TransformTimeSpan : Transform<double>
|
private class TransformTimeSpan : Transform<double>
|
||||||
{
|
{
|
||||||
public override double CurrentValue
|
public override double CurrentValue
|
||||||
|
@ -57,17 +57,23 @@
|
|||||||
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
||||||
<Compile Include="MathUtils\FastRandom.cs" />
|
<Compile Include="MathUtils\FastRandom.cs" />
|
||||||
<Compile Include="Judgements\HitWindows.cs" />
|
<Compile Include="Judgements\HitWindows.cs" />
|
||||||
|
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
||||||
|
<Compile Include="Judgements\HoldNoteTickJudgement.cs" />
|
||||||
<Compile Include="Judgements\ManiaHitResult.cs" />
|
<Compile Include="Judgements\ManiaHitResult.cs" />
|
||||||
<Compile Include="Judgements\ManiaJudgement.cs" />
|
<Compile Include="Judgements\ManiaJudgement.cs" />
|
||||||
<Compile Include="ManiaDifficultyCalculator.cs" />
|
<Compile Include="ManiaDifficultyCalculator.cs" />
|
||||||
|
<Compile Include="Objects\Drawables\DrawableBarLine.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableHoldNote.cs" />
|
<Compile Include="Objects\Drawables\DrawableHoldNote.cs" />
|
||||||
|
<Compile Include="Objects\Drawables\DrawableHoldNoteTick.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" />
|
<Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableNote.cs" />
|
<Compile Include="Objects\Drawables\DrawableNote.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" />
|
<Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\NotePiece.cs" />
|
<Compile Include="Objects\Drawables\Pieces\NotePiece.cs" />
|
||||||
<Compile Include="Objects\Types\IHasColumn.cs" />
|
<Compile Include="Objects\Types\IHasColumn.cs" />
|
||||||
<Compile Include="Scoring\ManiaScoreProcessor.cs" />
|
<Compile Include="Scoring\ManiaScoreProcessor.cs" />
|
||||||
|
<Compile Include="Objects\BarLine.cs" />
|
||||||
<Compile Include="Objects\HoldNote.cs" />
|
<Compile Include="Objects\HoldNote.cs" />
|
||||||
|
<Compile Include="Objects\HoldNoteTick.cs" />
|
||||||
<Compile Include="Objects\ManiaHitObject.cs" />
|
<Compile Include="Objects\ManiaHitObject.cs" />
|
||||||
<Compile Include="Objects\Note.cs" />
|
<Compile Include="Objects\Note.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
@ -39,6 +39,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class OsuModDaycore : ModDaycore
|
||||||
|
{
|
||||||
|
public override double ScoreMultiplier => 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
public class OsuModDoubleTime : ModDoubleTime
|
public class OsuModDoubleTime : ModDoubleTime
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
@ -46,7 +46,14 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
{
|
{
|
||||||
new OsuModEasy(),
|
new OsuModEasy(),
|
||||||
new OsuModNoFail(),
|
new OsuModNoFail(),
|
||||||
|
new MultiMod
|
||||||
|
{
|
||||||
|
Mods = new Mod[]
|
||||||
|
{
|
||||||
new OsuModHalfTime(),
|
new OsuModHalfTime(),
|
||||||
|
new OsuModDaycore(),
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.DifficultyIncrease:
|
case ModType.DifficultyIncrease:
|
||||||
|
@ -37,6 +37,11 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TaikoModDaycore : ModDaycore
|
||||||
|
{
|
||||||
|
public override double ScoreMultiplier => 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
public class TaikoModDoubleTime : ModDoubleTime
|
public class TaikoModDoubleTime : ModDoubleTime
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
@ -28,7 +28,14 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
{
|
{
|
||||||
new TaikoModEasy(),
|
new TaikoModEasy(),
|
||||||
new TaikoModNoFail(),
|
new TaikoModNoFail(),
|
||||||
|
new MultiMod
|
||||||
|
{
|
||||||
|
Mods = new Mod[]
|
||||||
|
{
|
||||||
new TaikoModHalfTime(),
|
new TaikoModHalfTime(),
|
||||||
|
new TaikoModDaycore(),
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.DifficultyIncrease:
|
case ModType.DifficultyIncrease:
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
Assert.IsTrue(File.Exists(temp));
|
Assert.IsTrue(File.Exists(temp));
|
||||||
|
|
||||||
var importer = new BeatmapIPCChannel(client);
|
var importer = new BeatmapIPCChannel(client);
|
||||||
if (!importer.ImportAsync(temp).Wait(5000))
|
if (!importer.ImportAsync(temp).Wait(10000))
|
||||||
Assert.Fail(@"IPC took too long to send");
|
Assert.Fail(@"IPC took too long to send");
|
||||||
|
|
||||||
ensureLoaded(host);
|
ensureLoaded(host);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
@ -31,6 +32,8 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
private ConvertHitObjectParser parser;
|
private ConvertHitObjectParser parser;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, string> variables = new Dictionary<string, string>();
|
||||||
|
|
||||||
private LegacySampleBank defaultSampleBank;
|
private LegacySampleBank defaultSampleBank;
|
||||||
private int defaultSampleVolume = 100;
|
private int defaultSampleVolume = 100;
|
||||||
|
|
||||||
@ -56,36 +59,39 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
TimingPoints,
|
TimingPoints,
|
||||||
Colours,
|
Colours,
|
||||||
HitObjects,
|
HitObjects,
|
||||||
|
Variables,
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleGeneral(Beatmap beatmap, string key, string val)
|
private void handleGeneral(Beatmap beatmap, string line)
|
||||||
{
|
{
|
||||||
|
var pair = splitKeyVal(line, ':');
|
||||||
|
|
||||||
var metadata = beatmap.BeatmapInfo.Metadata;
|
var metadata = beatmap.BeatmapInfo.Metadata;
|
||||||
switch (key)
|
switch (pair.Key)
|
||||||
{
|
{
|
||||||
case @"AudioFilename":
|
case @"AudioFilename":
|
||||||
metadata.AudioFile = val;
|
metadata.AudioFile = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"AudioLeadIn":
|
case @"AudioLeadIn":
|
||||||
beatmap.BeatmapInfo.AudioLeadIn = int.Parse(val);
|
beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"PreviewTime":
|
case @"PreviewTime":
|
||||||
metadata.PreviewTime = int.Parse(val);
|
metadata.PreviewTime = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"Countdown":
|
case @"Countdown":
|
||||||
beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1;
|
beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1;
|
||||||
break;
|
break;
|
||||||
case @"SampleSet":
|
case @"SampleSet":
|
||||||
defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), val);
|
defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"SampleVolume":
|
case @"SampleVolume":
|
||||||
defaultSampleVolume = int.Parse(val);
|
defaultSampleVolume = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"StackLeniency":
|
case @"StackLeniency":
|
||||||
beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo);
|
beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
case @"Mode":
|
case @"Mode":
|
||||||
beatmap.BeatmapInfo.RulesetID = int.Parse(val);
|
beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value);
|
||||||
|
|
||||||
switch (beatmap.BeatmapInfo.RulesetID)
|
switch (beatmap.BeatmapInfo.RulesetID)
|
||||||
{
|
{
|
||||||
@ -104,107 +110,135 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case @"LetterboxInBreaks":
|
case @"LetterboxInBreaks":
|
||||||
beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(val) == 1;
|
beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1;
|
||||||
break;
|
break;
|
||||||
case @"SpecialStyle":
|
case @"SpecialStyle":
|
||||||
beatmap.BeatmapInfo.SpecialStyle = int.Parse(val) == 1;
|
beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1;
|
||||||
break;
|
break;
|
||||||
case @"WidescreenStoryboard":
|
case @"WidescreenStoryboard":
|
||||||
beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(val) == 1;
|
beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleEditor(Beatmap beatmap, string key, string val)
|
private void handleEditor(Beatmap beatmap, string line)
|
||||||
{
|
{
|
||||||
switch (key)
|
var pair = splitKeyVal(line, ':');
|
||||||
|
|
||||||
|
switch (pair.Key)
|
||||||
{
|
{
|
||||||
case @"Bookmarks":
|
case @"Bookmarks":
|
||||||
beatmap.BeatmapInfo.StoredBookmarks = val;
|
beatmap.BeatmapInfo.StoredBookmarks = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"DistanceSpacing":
|
case @"DistanceSpacing":
|
||||||
beatmap.BeatmapInfo.DistanceSpacing = double.Parse(val, NumberFormatInfo.InvariantInfo);
|
beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
case @"BeatDivisor":
|
case @"BeatDivisor":
|
||||||
beatmap.BeatmapInfo.BeatDivisor = int.Parse(val);
|
beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"GridSize":
|
case @"GridSize":
|
||||||
beatmap.BeatmapInfo.GridSize = int.Parse(val);
|
beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"TimelineZoom":
|
case @"TimelineZoom":
|
||||||
beatmap.BeatmapInfo.TimelineZoom = double.Parse(val, NumberFormatInfo.InvariantInfo);
|
beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleMetadata(Beatmap beatmap, string key, string val)
|
private void handleMetadata(Beatmap beatmap, string line)
|
||||||
{
|
{
|
||||||
|
var pair = splitKeyVal(line, ':');
|
||||||
|
|
||||||
var metadata = beatmap.BeatmapInfo.Metadata;
|
var metadata = beatmap.BeatmapInfo.Metadata;
|
||||||
switch (key)
|
switch (pair.Key)
|
||||||
{
|
{
|
||||||
case @"Title":
|
case @"Title":
|
||||||
metadata.Title = val;
|
metadata.Title = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"TitleUnicode":
|
case @"TitleUnicode":
|
||||||
metadata.TitleUnicode = val;
|
metadata.TitleUnicode = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"Artist":
|
case @"Artist":
|
||||||
metadata.Artist = val;
|
metadata.Artist = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"ArtistUnicode":
|
case @"ArtistUnicode":
|
||||||
metadata.ArtistUnicode = val;
|
metadata.ArtistUnicode = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"Creator":
|
case @"Creator":
|
||||||
metadata.Author = val;
|
metadata.Author = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"Version":
|
case @"Version":
|
||||||
beatmap.BeatmapInfo.Version = val;
|
beatmap.BeatmapInfo.Version = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"Source":
|
case @"Source":
|
||||||
beatmap.BeatmapInfo.Metadata.Source = val;
|
beatmap.BeatmapInfo.Metadata.Source = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"Tags":
|
case @"Tags":
|
||||||
beatmap.BeatmapInfo.Metadata.Tags = val;
|
beatmap.BeatmapInfo.Metadata.Tags = pair.Value;
|
||||||
break;
|
break;
|
||||||
case @"BeatmapID":
|
case @"BeatmapID":
|
||||||
beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(val);
|
beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"BeatmapSetID":
|
case @"BeatmapSetID":
|
||||||
beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(val);
|
beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value);
|
||||||
metadata.OnlineBeatmapSetID = int.Parse(val);
|
metadata.OnlineBeatmapSetID = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDifficulty(Beatmap beatmap, string key, string val)
|
private void handleDifficulty(Beatmap beatmap, string line)
|
||||||
{
|
{
|
||||||
|
var pair = splitKeyVal(line, ':');
|
||||||
|
|
||||||
var difficulty = beatmap.BeatmapInfo.Difficulty;
|
var difficulty = beatmap.BeatmapInfo.Difficulty;
|
||||||
switch (key)
|
switch (pair.Key)
|
||||||
{
|
{
|
||||||
case @"HPDrainRate":
|
case @"HPDrainRate":
|
||||||
difficulty.DrainRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
|
difficulty.DrainRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
case @"CircleSize":
|
case @"CircleSize":
|
||||||
difficulty.CircleSize = float.Parse(val, NumberFormatInfo.InvariantInfo);
|
difficulty.CircleSize = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
case @"OverallDifficulty":
|
case @"OverallDifficulty":
|
||||||
difficulty.OverallDifficulty = float.Parse(val, NumberFormatInfo.InvariantInfo);
|
difficulty.OverallDifficulty = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
case @"ApproachRate":
|
case @"ApproachRate":
|
||||||
difficulty.ApproachRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
|
difficulty.ApproachRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
case @"SliderMultiplier":
|
case @"SliderMultiplier":
|
||||||
difficulty.SliderMultiplier = float.Parse(val, NumberFormatInfo.InvariantInfo);
|
difficulty.SliderMultiplier = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
case @"SliderTickRate":
|
case @"SliderTickRate":
|
||||||
difficulty.SliderTickRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
|
difficulty.SliderTickRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleEvents(Beatmap beatmap, string val)
|
/// <summary>
|
||||||
|
/// Decodes any beatmap variables present in a line into their real values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line">The line which may contains variables.</param>
|
||||||
|
private void decodeVariables(ref string line)
|
||||||
{
|
{
|
||||||
string[] split = val.Split(',');
|
while (line.IndexOf('$') >= 0)
|
||||||
|
{
|
||||||
|
string[] split = line.Split(',');
|
||||||
|
for (int i = 0; i < split.Length; i++)
|
||||||
|
{
|
||||||
|
var item = split[i];
|
||||||
|
if (item.StartsWith("$") && variables.ContainsKey(item))
|
||||||
|
split[i] = variables[item];
|
||||||
|
}
|
||||||
|
|
||||||
|
line = string.Join(",", split);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleEvents(Beatmap beatmap, string line)
|
||||||
|
{
|
||||||
|
decodeVariables(ref line);
|
||||||
|
|
||||||
|
string[] split = line.Split(',');
|
||||||
|
|
||||||
EventType type;
|
EventType type;
|
||||||
if (!Enum.TryParse(split[0], out type))
|
if (!Enum.TryParse(split[0], out type))
|
||||||
@ -236,9 +270,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTimingPoints(Beatmap beatmap, string val)
|
private void handleTimingPoints(Beatmap beatmap, string line)
|
||||||
{
|
{
|
||||||
string[] split = val.Split(',');
|
string[] split = line.Split(',');
|
||||||
|
|
||||||
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
||||||
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
||||||
@ -321,12 +355,14 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
|
private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours)
|
||||||
{
|
{
|
||||||
string[] split = val.Split(',');
|
var pair = splitKeyVal(line, ':');
|
||||||
|
|
||||||
|
string[] split = pair.Value.Split(',');
|
||||||
|
|
||||||
if (split.Length != 3)
|
if (split.Length != 3)
|
||||||
throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {val}");
|
throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}");
|
||||||
|
|
||||||
byte r, g, b;
|
byte r, g, b;
|
||||||
if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b))
|
if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b))
|
||||||
@ -339,7 +375,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Note: the combo index specified in the beatmap is discarded
|
// Note: the combo index specified in the beatmap is discarded
|
||||||
if (key.StartsWith(@"Combo"))
|
if (pair.Key.StartsWith(@"Combo"))
|
||||||
{
|
{
|
||||||
beatmap.ComboColors.Add(new Color4
|
beatmap.ComboColors.Add(new Color4
|
||||||
{
|
{
|
||||||
@ -351,6 +387,12 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleVariables(string line)
|
||||||
|
{
|
||||||
|
var pair = splitKeyVal(line, '=');
|
||||||
|
variables[pair.Key] = pair.Value;
|
||||||
|
}
|
||||||
|
|
||||||
protected override Beatmap ParseFile(StreamReader stream)
|
protected override Beatmap ParseFile(StreamReader stream)
|
||||||
{
|
{
|
||||||
return new LegacyBeatmap(base.ParseFile(stream));
|
return new LegacyBeatmap(base.ParseFile(stream));
|
||||||
@ -390,44 +432,53 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string val = line, key = null;
|
|
||||||
if (section != Section.Events && section != Section.TimingPoints && section != Section.HitObjects)
|
|
||||||
{
|
|
||||||
key = val.Remove(val.IndexOf(':')).Trim();
|
|
||||||
val = val.Substring(val.IndexOf(':') + 1).Trim();
|
|
||||||
}
|
|
||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
case Section.General:
|
case Section.General:
|
||||||
handleGeneral(beatmap, key, val);
|
handleGeneral(beatmap, line);
|
||||||
break;
|
break;
|
||||||
case Section.Editor:
|
case Section.Editor:
|
||||||
handleEditor(beatmap, key, val);
|
handleEditor(beatmap, line);
|
||||||
break;
|
break;
|
||||||
case Section.Metadata:
|
case Section.Metadata:
|
||||||
handleMetadata(beatmap, key, val);
|
handleMetadata(beatmap, line);
|
||||||
break;
|
break;
|
||||||
case Section.Difficulty:
|
case Section.Difficulty:
|
||||||
handleDifficulty(beatmap, key, val);
|
handleDifficulty(beatmap, line);
|
||||||
break;
|
break;
|
||||||
case Section.Events:
|
case Section.Events:
|
||||||
handleEvents(beatmap, val);
|
handleEvents(beatmap, line);
|
||||||
break;
|
break;
|
||||||
case Section.TimingPoints:
|
case Section.TimingPoints:
|
||||||
handleTimingPoints(beatmap, val);
|
handleTimingPoints(beatmap, line);
|
||||||
break;
|
break;
|
||||||
case Section.Colours:
|
case Section.Colours:
|
||||||
handleColours(beatmap, key, val, ref hasCustomColours);
|
handleColours(beatmap, line, ref hasCustomColours);
|
||||||
break;
|
break;
|
||||||
case Section.HitObjects:
|
case Section.HitObjects:
|
||||||
var obj = parser.Parse(val);
|
var obj = parser.Parse(line);
|
||||||
|
|
||||||
if (obj != null)
|
if (obj != null)
|
||||||
beatmap.HitObjects.Add(obj);
|
beatmap.HitObjects.Add(obj);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case Section.Variables:
|
||||||
|
handleVariables(line);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var hitObject in beatmap.HitObjects)
|
||||||
|
hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyValuePair<string, string> splitKeyVal(string line, char separator)
|
||||||
|
{
|
||||||
|
return new KeyValuePair<string, string>
|
||||||
|
(
|
||||||
|
line.Remove(line.IndexOf(separator)).Trim(),
|
||||||
|
line.Substring(line.IndexOf(separator) + 1).Trim()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum LegacySampleBank
|
internal enum LegacySampleBank
|
||||||
|
@ -20,6 +20,8 @@ namespace osu.Game.Configuration
|
|||||||
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10);
|
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10);
|
||||||
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10);
|
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10);
|
||||||
|
|
||||||
|
Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation);
|
||||||
|
|
||||||
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
|
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
|
||||||
|
|
||||||
// Online settings
|
// Online settings
|
||||||
@ -69,6 +71,9 @@ namespace osu.Game.Configuration
|
|||||||
Set(OsuSetting.ShowInterface, true);
|
Set(OsuSetting.ShowInterface, true);
|
||||||
Set(OsuSetting.KeyOverlay, false);
|
Set(OsuSetting.KeyOverlay, false);
|
||||||
|
|
||||||
|
Set(OsuSetting.FloatingComments, false);
|
||||||
|
Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
|
|
||||||
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
|
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
|
||||||
@ -88,6 +93,8 @@ namespace osu.Game.Configuration
|
|||||||
AutoCursorSize,
|
AutoCursorSize,
|
||||||
DimLevel,
|
DimLevel,
|
||||||
KeyOverlay,
|
KeyOverlay,
|
||||||
|
FloatingComments,
|
||||||
|
PlaybackSpeed,
|
||||||
ShowInterface,
|
ShowInterface,
|
||||||
MouseDisableButtons,
|
MouseDisableButtons,
|
||||||
MouseDisableWheel,
|
MouseDisableWheel,
|
||||||
@ -102,6 +109,7 @@ namespace osu.Game.Configuration
|
|||||||
SaveUsername,
|
SaveUsername,
|
||||||
DisplayStarsMinimum,
|
DisplayStarsMinimum,
|
||||||
DisplayStarsMaximum,
|
DisplayStarsMaximum,
|
||||||
|
SelectionRandomType,
|
||||||
SnakingInSliders,
|
SnakingInSliders,
|
||||||
SnakingOutSliders,
|
SnakingOutSliders,
|
||||||
ShowFpsDisplay,
|
ShowFpsDisplay,
|
||||||
|
15
osu.Game/Configuration/SelectionRandomType.cs
Normal file
15
osu.Game/Configuration/SelectionRandomType.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// 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.ComponentModel;
|
||||||
|
|
||||||
|
namespace osu.Game.Configuration
|
||||||
|
{
|
||||||
|
public enum SelectionRandomType
|
||||||
|
{
|
||||||
|
[Description("Never repeat")]
|
||||||
|
RandomPermutation,
|
||||||
|
[Description("Random")]
|
||||||
|
Random
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,13 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
public class Triangles : Drawable
|
public class Triangles : Drawable
|
||||||
{
|
{
|
||||||
private const float triangle_size = 100;
|
private const float triangle_size = 100;
|
||||||
|
private const float base_velocity = 50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many screen-space pixels are smoothed over.
|
||||||
|
/// Same behavior as Sprite's EdgeSmoothness.
|
||||||
|
/// </summary>
|
||||||
|
private const float edge_smoothness = 1;
|
||||||
|
|
||||||
public override bool HandleInput => false;
|
public override bool HandleInput => false;
|
||||||
|
|
||||||
@ -103,31 +110,34 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
|
|
||||||
Invalidate(Invalidation.DrawNode, shallPropagate: false);
|
Invalidate(Invalidation.DrawNode, shallPropagate: false);
|
||||||
|
|
||||||
for (int i = 0; i < parts.Count; i++)
|
if (CreateNewTriangles)
|
||||||
{
|
addTriangles(false);
|
||||||
TriangleParticle newParticle = parts[i];
|
|
||||||
|
|
||||||
float adjustedAlpha = HideAlphaDiscrepancies ?
|
float adjustedAlpha = HideAlphaDiscrepancies ?
|
||||||
// Cubically scale alpha to make it drop off more sharply.
|
// Cubically scale alpha to make it drop off more sharply.
|
||||||
(float)Math.Pow(DrawInfo.Colour.AverageColour.Linear.A, 3) :
|
(float)Math.Pow(DrawInfo.Colour.AverageColour.Linear.A, 3) :
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
float elapsedSeconds = (float)Time.Elapsed / 1000;
|
||||||
|
// Since position is relative, the velocity needs to scale inversely with DrawHeight.
|
||||||
|
// Since we will later multiply by the scale of individual triangles we normalize by
|
||||||
|
// dividing by triangleScale.
|
||||||
|
float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * triangleScale);
|
||||||
|
|
||||||
newParticle.Position += new Vector2(0, -(parts[i].Scale * (50 / DrawHeight)) / triangleScale * Velocity) * ((float)Time.Elapsed / 950);
|
for (int i = 0; i < parts.Count; i++)
|
||||||
|
{
|
||||||
|
TriangleParticle newParticle = parts[i];
|
||||||
|
|
||||||
|
// Scale moved distance by the size of the triangle. Smaller triangles should move more slowly.
|
||||||
|
newParticle.Position.Y += parts[i].Scale * movedDistance;
|
||||||
newParticle.Colour.A = adjustedAlpha;
|
newParticle.Colour.A = adjustedAlpha;
|
||||||
|
|
||||||
parts[i] = newParticle;
|
parts[i] = newParticle;
|
||||||
|
|
||||||
if (!CreateNewTriangles)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * 0.866f / DrawHeight;
|
float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * 0.866f / DrawHeight;
|
||||||
|
|
||||||
if (bottomPos < 0)
|
if (bottomPos < 0)
|
||||||
parts.RemoveAt(i);
|
parts.RemoveAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTriangles(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addTriangles(bool randomY)
|
private void addTriangles(bool randomY)
|
||||||
@ -211,20 +221,28 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
Shader.Bind();
|
Shader.Bind();
|
||||||
Texture.TextureGL.Bind();
|
Texture.TextureGL.Bind();
|
||||||
|
|
||||||
|
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
|
||||||
|
|
||||||
foreach (TriangleParticle particle in Parts)
|
foreach (TriangleParticle particle in Parts)
|
||||||
{
|
{
|
||||||
var offset = new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f);
|
var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f);
|
||||||
|
var size = new Vector2(2 * offset.X, offset.Y);
|
||||||
|
|
||||||
var triangle = new Triangle(
|
var triangle = new Triangle(
|
||||||
particle.Position * Size * DrawInfo.Matrix,
|
particle.Position * Size * DrawInfo.Matrix,
|
||||||
(particle.Position * Size + offset * triangle_size) * DrawInfo.Matrix,
|
(particle.Position * Size + offset) * DrawInfo.Matrix,
|
||||||
(particle.Position * Size + new Vector2(-offset.X, offset.Y) * triangle_size) * DrawInfo.Matrix
|
(particle.Position * Size + new Vector2(-offset.X, offset.Y)) * DrawInfo.Matrix
|
||||||
);
|
);
|
||||||
|
|
||||||
ColourInfo colourInfo = DrawInfo.Colour;
|
ColourInfo colourInfo = DrawInfo.Colour;
|
||||||
colourInfo.ApplyChild(particle.Colour);
|
colourInfo.ApplyChild(particle.Colour);
|
||||||
|
|
||||||
Texture.DrawTriangle(triangle, colourInfo, null, Shared.VertexBatch.Add);
|
Texture.DrawTriangle(
|
||||||
|
triangle,
|
||||||
|
colourInfo,
|
||||||
|
null,
|
||||||
|
Shared.VertexBatch.Add,
|
||||||
|
Vector2.Divide(localInflationAmount, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader.Unbind();
|
Shader.Unbind();
|
||||||
|
@ -11,6 +11,6 @@ namespace osu.Game.Graphics.Containers
|
|||||||
public class ReverseDepthFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable
|
public class ReverseDepthFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable
|
||||||
{
|
{
|
||||||
protected override IComparer<Drawable> DepthComparer => new ReverseCreationOrderDepthComparer();
|
protected override IComparer<Drawable> DepthComparer => new ReverseCreationOrderDepthComparer();
|
||||||
protected override IEnumerable<T> FlowingChildren => base.FlowingChildren.Reverse();
|
protected override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Reverse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
private Container cursorContainer;
|
private Container cursorContainer;
|
||||||
private Bindable<double> cursorScale;
|
private Bindable<double> cursorScale;
|
||||||
|
private const float base_scale = 0.15f;
|
||||||
|
|
||||||
public Sprite AdditiveLayer;
|
public Sprite AdditiveLayer;
|
||||||
|
|
||||||
@ -108,17 +109,15 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
cursorContainer = new Container
|
cursorContainer = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(32),
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Sprite
|
new Sprite
|
||||||
{
|
{
|
||||||
FillMode = FillMode.Fit,
|
|
||||||
Texture = textures.Get(@"Cursor/menu-cursor"),
|
Texture = textures.Get(@"Cursor/menu-cursor"),
|
||||||
},
|
},
|
||||||
AdditiveLayer = new Sprite
|
AdditiveLayer = new Sprite
|
||||||
{
|
{
|
||||||
FillMode = FillMode.Fit,
|
|
||||||
BlendingMode = BlendingMode.Additive,
|
BlendingMode = BlendingMode.Additive,
|
||||||
Colour = colour.Pink,
|
Colour = colour.Pink,
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
@ -129,7 +128,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
};
|
};
|
||||||
|
|
||||||
cursorScale = config.GetBindable<double>(OsuSetting.MenuCursorSize);
|
cursorScale = config.GetBindable<double>(OsuSetting.MenuCursorSize);
|
||||||
cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale);
|
cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale * base_scale);
|
||||||
cursorScale.TriggerChange();
|
cursorScale.TriggerChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
109
osu.Game/Graphics/Cursor/OsuTooltipContainer.cs
Normal file
109
osu.Game/Graphics/Cursor/OsuTooltipContainer.cs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// 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.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.Cursor
|
||||||
|
{
|
||||||
|
public class OsuTooltipContainer : TooltipContainer
|
||||||
|
{
|
||||||
|
protected override Tooltip CreateTooltip() => new OsuTooltip();
|
||||||
|
|
||||||
|
public OsuTooltipContainer(CursorContainer cursor) : base(cursor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OsuTooltip : Tooltip
|
||||||
|
{
|
||||||
|
private readonly Box background;
|
||||||
|
private readonly OsuSpriteText text;
|
||||||
|
private bool instantMovement = true;
|
||||||
|
|
||||||
|
public override string TooltipText
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == text.Text) return;
|
||||||
|
|
||||||
|
text.Text = value;
|
||||||
|
if (IsPresent)
|
||||||
|
{
|
||||||
|
AutoSizeDuration = 250;
|
||||||
|
background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
AutoSizeDuration = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float text_size = 16;
|
||||||
|
|
||||||
|
public OsuTooltip()
|
||||||
|
{
|
||||||
|
AutoSizeEasing = EasingTypes.OutQuint;
|
||||||
|
|
||||||
|
CornerRadius = 5;
|
||||||
|
Masking = true;
|
||||||
|
EdgeEffect = new EdgeEffect
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Colour = Color4.Black.Opacity(40),
|
||||||
|
Radius = 5,
|
||||||
|
};
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0.9f,
|
||||||
|
},
|
||||||
|
text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
TextSize = text_size,
|
||||||
|
Padding = new MarginPadding(5),
|
||||||
|
Font = @"Exo2.0-Regular",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colour)
|
||||||
|
{
|
||||||
|
background.Colour = colour.Gray3;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
instantMovement |= !IsPresent;
|
||||||
|
FadeIn(500, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
using (BeginDelayedSequence(150))
|
||||||
|
FadeOut(500, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Move(Vector2 pos)
|
||||||
|
{
|
||||||
|
if (instantMovement)
|
||||||
|
{
|
||||||
|
Position = pos;
|
||||||
|
instantMovement = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoveTo(pos, 200, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,157 +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 OpenTK;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Cursor;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Threading;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
|
||||||
{
|
|
||||||
public class TooltipContainer : Container
|
|
||||||
{
|
|
||||||
private readonly CursorContainer cursor;
|
|
||||||
private readonly Tooltip tooltip;
|
|
||||||
|
|
||||||
private ScheduledDelegate findTooltipTask;
|
|
||||||
private UserInputManager inputManager;
|
|
||||||
|
|
||||||
private const int default_appear_delay = 220;
|
|
||||||
|
|
||||||
private IHasTooltip currentlyDisplayed;
|
|
||||||
|
|
||||||
public TooltipContainer(CursorContainer cursor)
|
|
||||||
{
|
|
||||||
this.cursor = cursor;
|
|
||||||
AlwaysPresent = true;
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
Add(tooltip = new Tooltip { Alpha = 0 });
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(UserInputManager input)
|
|
||||||
{
|
|
||||||
inputManager = input;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
if (tooltip.IsPresent)
|
|
||||||
{
|
|
||||||
if (currentlyDisplayed != null)
|
|
||||||
tooltip.TooltipText = currentlyDisplayed.TooltipText;
|
|
||||||
|
|
||||||
//update the position of the displayed tooltip.
|
|
||||||
tooltip.Position = ToLocalSpace(cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre) + new Vector2(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
|
||||||
{
|
|
||||||
updateTooltipState(state);
|
|
||||||
return base.OnMouseUp(state, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnMouseMove(InputState state)
|
|
||||||
{
|
|
||||||
updateTooltipState(state);
|
|
||||||
return base.OnMouseMove(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTooltipState(InputState state)
|
|
||||||
{
|
|
||||||
if (currentlyDisplayed?.Hovering != true)
|
|
||||||
{
|
|
||||||
if (currentlyDisplayed != null && !state.Mouse.HasMainButtonPressed)
|
|
||||||
{
|
|
||||||
tooltip.Delay(150);
|
|
||||||
tooltip.FadeOut(500, EasingTypes.OutQuint);
|
|
||||||
currentlyDisplayed = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
findTooltipTask?.Cancel();
|
|
||||||
findTooltipTask = Scheduler.AddDelayed(delegate
|
|
||||||
{
|
|
||||||
var tooltipTarget = inputManager.HoveredDrawables.OfType<IHasTooltip>().FirstOrDefault();
|
|
||||||
|
|
||||||
if (tooltipTarget == null) return;
|
|
||||||
|
|
||||||
tooltip.TooltipText = tooltipTarget.TooltipText;
|
|
||||||
tooltip.FadeIn(500, EasingTypes.OutQuint);
|
|
||||||
|
|
||||||
currentlyDisplayed = tooltipTarget;
|
|
||||||
}, (1 - tooltip.Alpha) * default_appear_delay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Tooltip : Container
|
|
||||||
{
|
|
||||||
private readonly Box background;
|
|
||||||
private readonly OsuSpriteText text;
|
|
||||||
|
|
||||||
public string TooltipText
|
|
||||||
{
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == text.Text) return;
|
|
||||||
|
|
||||||
text.Text = value;
|
|
||||||
if (Alpha > 0)
|
|
||||||
{
|
|
||||||
AutoSizeDuration = 250;
|
|
||||||
background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
AutoSizeDuration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool HandleInput => false;
|
|
||||||
|
|
||||||
private const float text_size = 16;
|
|
||||||
|
|
||||||
public Tooltip()
|
|
||||||
{
|
|
||||||
AutoSizeEasing = EasingTypes.OutQuint;
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
CornerRadius = 5;
|
|
||||||
Masking = true;
|
|
||||||
EdgeEffect = new EdgeEffect
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Colour = Color4.Black.Opacity(40),
|
|
||||||
Radius = 5,
|
|
||||||
};
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
background = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0.9f,
|
|
||||||
},
|
|
||||||
text = new OsuSpriteText
|
|
||||||
{
|
|
||||||
TextSize = text_size,
|
|
||||||
Padding = new MarginPadding(5),
|
|
||||||
Font = @"Exo2.0-Regular",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colour)
|
|
||||||
{
|
|
||||||
background.Colour = colour.Gray3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics
|
|
||||||
{
|
|
||||||
public interface IHasTooltip : IDrawable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Tooltip that shows when hovering the drawable
|
|
||||||
/// </summary>
|
|
||||||
string TooltipText { get; }
|
|
||||||
}
|
|
||||||
}
|
|
84
osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
Normal file
84
osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using OpenTK;
|
||||||
|
using osu.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class BreadcrumbControl<T> : OsuTabControl<T>
|
||||||
|
{
|
||||||
|
private const float padding = 10;
|
||||||
|
|
||||||
|
protected override TabItem<T> CreateTabItem(T value) => new BreadcrumbTabItem(value);
|
||||||
|
|
||||||
|
public BreadcrumbControl()
|
||||||
|
{
|
||||||
|
Height = 26;
|
||||||
|
TabContainer.Spacing = new Vector2(padding, 0f);
|
||||||
|
Current.ValueChanged += tab =>
|
||||||
|
{
|
||||||
|
foreach (var t in TabContainer.Children.OfType<BreadcrumbTabItem>())
|
||||||
|
{
|
||||||
|
var tIndex = TabContainer.IndexOf(t);
|
||||||
|
var tabIndex = TabContainer.IndexOf(TabMap[tab]);
|
||||||
|
|
||||||
|
t.State = tIndex < tabIndex ? Visibility.Hidden : Visibility.Visible;
|
||||||
|
t.Chevron.FadeTo(tIndex <= tabIndex ? 0f : 1f, 500, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility>
|
||||||
|
{
|
||||||
|
public readonly TextAwesome Chevron;
|
||||||
|
|
||||||
|
//don't allow clicking between transitions and don't make the chevron clickable
|
||||||
|
protected override bool InternalContains(Vector2 screenSpacePos) => Alpha == 1f && Text.Contains(screenSpacePos);
|
||||||
|
public override bool HandleInput => State == Visibility.Visible;
|
||||||
|
|
||||||
|
private Visibility state;
|
||||||
|
public Visibility State
|
||||||
|
{
|
||||||
|
get { return state; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == state) return;
|
||||||
|
state = value;
|
||||||
|
|
||||||
|
const float transition_duration = 500;
|
||||||
|
|
||||||
|
if (State == Visibility.Visible)
|
||||||
|
{
|
||||||
|
FadeIn(transition_duration, EasingTypes.OutQuint);
|
||||||
|
ScaleTo(new Vector2(1f), transition_duration, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FadeOut(transition_duration, EasingTypes.OutQuint);
|
||||||
|
ScaleTo(new Vector2(0.8f, 1f), transition_duration, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BreadcrumbTabItem(T value) : base(value)
|
||||||
|
{
|
||||||
|
Text.TextSize = 16;
|
||||||
|
Padding = new MarginPadding { Right = padding + 8 }; //padding + chevron width
|
||||||
|
Add(Chevron = new TextAwesome
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
TextSize = 12,
|
||||||
|
Icon = FontAwesome.fa_chevron_right,
|
||||||
|
Margin = new MarginPadding { Left = padding },
|
||||||
|
Alpha = 0f,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -23,16 +24,23 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
focus = value;
|
focus = value;
|
||||||
if (!focus)
|
if (!focus && HasFocus)
|
||||||
TriggerFocusLost();
|
inputManager.ChangeFocus(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
private InputManager inputManager;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
var result = base.OnFocus(state);
|
this.inputManager = inputManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFocus(InputState state)
|
||||||
|
{
|
||||||
|
base.OnFocus(state);
|
||||||
BorderThickness = 0;
|
BorderThickness = 0;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFocusLost(InputState state)
|
protected override void OnFocusLost(InputState state)
|
||||||
@ -47,6 +55,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
base.OnFocusLost(state);
|
base.OnFocusLost(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool RequestingFocus => HoldFocus;
|
public override bool RequestsFocus => HoldFocus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
osu.Game/Graphics/UserInterface/IconButton.cs
Normal file
114
osu.Game/Graphics/UserInterface/IconButton.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// 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.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class IconButton : ClickableContainer
|
||||||
|
{
|
||||||
|
private readonly TextAwesome icon;
|
||||||
|
private readonly Box hover;
|
||||||
|
private readonly Container content;
|
||||||
|
|
||||||
|
public FontAwesome Icon
|
||||||
|
{
|
||||||
|
get { return icon.Icon; }
|
||||||
|
set { icon.Icon = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float button_size = 30;
|
||||||
|
private Color4 flashColour;
|
||||||
|
|
||||||
|
public Vector2 IconScale
|
||||||
|
{
|
||||||
|
get { return icon.Scale; }
|
||||||
|
set { icon.Scale = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconButton()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
content = new Container
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Size = new Vector2 (button_size),
|
||||||
|
|
||||||
|
CornerRadius = 5,
|
||||||
|
Masking = true,
|
||||||
|
EdgeEffect = new EdgeEffect
|
||||||
|
{
|
||||||
|
Colour = Color4.Black.Opacity(0.04f),
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Radius = 5,
|
||||||
|
},
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
hover = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
|
icon = new TextAwesome
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
TextSize = 18,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
hover.Colour = colours.Yellow.Opacity(0.6f);
|
||||||
|
flashColour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(InputState state)
|
||||||
|
{
|
||||||
|
hover.FadeIn(500, EasingTypes.OutQuint);
|
||||||
|
return base.OnHover(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(InputState state)
|
||||||
|
{
|
||||||
|
hover.FadeOut(500, EasingTypes.OutQuint);
|
||||||
|
base.OnHoverLost(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnClick(InputState state)
|
||||||
|
{
|
||||||
|
hover.FlashColour(flashColour, 800, EasingTypes.OutQuint);
|
||||||
|
return base.OnClick(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
|
{
|
||||||
|
content.ScaleTo(0.75f, 2000, EasingTypes.OutQuint);
|
||||||
|
return base.OnMouseDown(state, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||||
|
{
|
||||||
|
content.ScaleTo(1, 1000, EasingTypes.OutElastic);
|
||||||
|
return base.OnMouseUp(state, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,13 +12,12 @@ using osu.Framework.Graphics.UserInterface;
|
|||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class Nub : CircularContainer, IHasCurrentValue<bool>
|
public class Nub : CircularContainer, IHasCurrentValue<bool>, IHasAccentColour
|
||||||
{
|
{
|
||||||
public const float COLLAPSED_SIZE = 20;
|
public const float COLLAPSED_SIZE = 20;
|
||||||
public const float EXPANDED_SIZE = 40;
|
public const float EXPANDED_SIZE = 40;
|
||||||
|
|
||||||
private const float border_width = 3;
|
private const float border_width = 3;
|
||||||
private Color4 glowingColour, idleColour;
|
|
||||||
|
|
||||||
public Nub()
|
public Nub()
|
||||||
{
|
{
|
||||||
@ -53,33 +52,41 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
Colour = idleColour = colours.Pink;
|
AccentColour = colours.Pink;
|
||||||
glowingColour = colours.PinkLighter;
|
GlowingAccentColour = colours.PinkLighter;
|
||||||
|
GlowColour = colours.PinkDarker;
|
||||||
|
|
||||||
EdgeEffect = new EdgeEffect
|
EdgeEffect = new EdgeEffect
|
||||||
{
|
{
|
||||||
Colour = colours.PinkDarker,
|
Colour = GlowColour,
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Radius = 10,
|
Radius = 10,
|
||||||
Roundness = 8,
|
Roundness = 8,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
FadeEdgeEffectTo(0);
|
FadeEdgeEffectTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool glowing;
|
||||||
public bool Glowing
|
public bool Glowing
|
||||||
{
|
{
|
||||||
|
get { return glowing; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
glowing = value;
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
FadeColour(glowingColour, 500, EasingTypes.OutQuint);
|
FadeColour(GlowingAccentColour, 500, EasingTypes.OutQuint);
|
||||||
FadeEdgeEffectTo(1, 500, EasingTypes.OutQuint);
|
FadeEdgeEffectTo(1, 500, EasingTypes.OutQuint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FadeEdgeEffectTo(0, 500);
|
FadeEdgeEffectTo(0, 500);
|
||||||
FadeColour(idleColour, 500);
|
FadeColour(AccentColour, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,5 +100,43 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Bindable<bool> Current { get; } = new Bindable<bool>();
|
public Bindable<bool> Current { get; } = new Bindable<bool>();
|
||||||
|
|
||||||
|
private Color4 accentColour;
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get { return accentColour; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
accentColour = value;
|
||||||
|
if (!Glowing)
|
||||||
|
Colour = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color4 glowingAccentColour;
|
||||||
|
public Color4 GlowingAccentColour
|
||||||
|
{
|
||||||
|
get { return glowingAccentColour; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
glowingAccentColour = value;
|
||||||
|
if (Glowing)
|
||||||
|
Colour = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color4 glowColour;
|
||||||
|
public Color4 GlowColour
|
||||||
|
{
|
||||||
|
get { return glowColour; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
glowColour = value;
|
||||||
|
|
||||||
|
var effect = EdgeEffect;
|
||||||
|
effect.Colour = value;
|
||||||
|
EdgeEffect = effect;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Nub nub;
|
protected readonly Nub Nub;
|
||||||
|
|
||||||
private readonly SpriteText labelSpriteText;
|
private readonly SpriteText labelSpriteText;
|
||||||
private SampleChannel sampleChecked;
|
private SampleChannel sampleChecked;
|
||||||
private SampleChannel sampleUnchecked;
|
private SampleChannel sampleUnchecked;
|
||||||
@ -64,7 +65,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
labelSpriteText = new OsuSpriteText(),
|
labelSpriteText = new OsuSpriteText(),
|
||||||
nub = new Nub
|
Nub = new Nub
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
@ -72,7 +73,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
nub.Current.BindTo(Current);
|
Nub.Current.BindTo(Current);
|
||||||
|
|
||||||
Current.ValueChanged += newValue =>
|
Current.ValueChanged += newValue =>
|
||||||
{
|
{
|
||||||
@ -90,15 +91,15 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
nub.Glowing = true;
|
Nub.Glowing = true;
|
||||||
nub.Expanded = true;
|
Nub.Expanded = true;
|
||||||
return base.OnHover(state);
|
return base.OnHover(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
nub.Glowing = false;
|
Nub.Glowing = false;
|
||||||
nub.Expanded = false;
|
Nub.Expanded = false;
|
||||||
base.OnHoverLost(state);
|
base.OnHoverLost(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
},
|
},
|
||||||
new OsuSpriteText {
|
Label = new OsuSpriteText {
|
||||||
Text = text,
|
Text = text,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
@ -85,6 +85,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private Color4? accentColour;
|
private Color4? accentColour;
|
||||||
|
|
||||||
protected readonly TextAwesome Chevron;
|
protected readonly TextAwesome Chevron;
|
||||||
|
protected readonly OsuSpriteText Label;
|
||||||
|
|
||||||
protected override void FormatForeground(bool hover = false)
|
protected override void FormatForeground(bool hover = false)
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
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.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
@ -11,17 +12,18 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class OsuSliderBar<T> : SliderBar<T>, IHasTooltip
|
public class OsuSliderBar<T> : SliderBar<T>, IHasTooltip, IHasAccentColour
|
||||||
where T : struct, IEquatable<T>
|
where T : struct, IEquatable<T>
|
||||||
{
|
{
|
||||||
private SampleChannel sample;
|
private SampleChannel sample;
|
||||||
private double lastSampleTime;
|
private double lastSampleTime;
|
||||||
private T lastSampleValue;
|
private T lastSampleValue;
|
||||||
|
|
||||||
private readonly Nub nub;
|
protected readonly Nub Nub;
|
||||||
private readonly Box leftBox;
|
private readonly Box leftBox;
|
||||||
private readonly Box rightBox;
|
private readonly Box rightBox;
|
||||||
|
|
||||||
@ -45,6 +47,18 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Color4 accentColour;
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get { return accentColour; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
accentColour = value;
|
||||||
|
leftBox.Colour = value;
|
||||||
|
rightBox.Colour = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public OsuSliderBar()
|
public OsuSliderBar()
|
||||||
{
|
{
|
||||||
Height = 12;
|
Height = 12;
|
||||||
@ -70,7 +84,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
},
|
},
|
||||||
nub = new Nub
|
Nub = new Nub
|
||||||
{
|
{
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Expanded = true,
|
Expanded = true,
|
||||||
@ -87,19 +101,18 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private void load(AudioManager audio, OsuColour colours)
|
private void load(AudioManager audio, OsuColour colours)
|
||||||
{
|
{
|
||||||
sample = audio.Sample.Get(@"Sliderbar/sliderbar");
|
sample = audio.Sample.Get(@"Sliderbar/sliderbar");
|
||||||
leftBox.Colour = colours.Pink;
|
AccentColour = colours.Pink;
|
||||||
rightBox.Colour = colours.Pink;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
nub.Glowing = true;
|
Nub.Glowing = true;
|
||||||
return base.OnHover(state);
|
return base.OnHover(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
nub.Glowing = false;
|
Nub.Glowing = false;
|
||||||
base.OnHoverLost(state);
|
base.OnHoverLost(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,13 +145,13 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
{
|
{
|
||||||
nub.Current.Value = true;
|
Nub.Current.Value = true;
|
||||||
return base.OnMouseDown(state, args);
|
return base.OnMouseDown(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||||
{
|
{
|
||||||
nub.Current.Value = false;
|
Nub.Current.Value = false;
|
||||||
return base.OnMouseUp(state, args);
|
return base.OnMouseUp(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,14 +159,14 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
leftBox.Scale = new Vector2(MathHelper.Clamp(
|
leftBox.Scale = new Vector2(MathHelper.Clamp(
|
||||||
nub.DrawPosition.X - nub.DrawWidth / 2, 0, DrawWidth), 1);
|
Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
|
||||||
rightBox.Scale = new Vector2(MathHelper.Clamp(
|
rightBox.Scale = new Vector2(MathHelper.Clamp(
|
||||||
DrawWidth - nub.DrawPosition.X - nub.DrawWidth / 2, 0, DrawWidth), 1);
|
DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateValue(float value)
|
protected override void UpdateValue(float value)
|
||||||
{
|
{
|
||||||
nub.MoveToX(RangePadding + UsableWidth * value, 250, EasingTypes.OutQuint);
|
Nub.MoveToX(RangePadding + UsableWidth * value, 250, EasingTypes.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,11 +45,10 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
BorderColour = colour.Yellow;
|
BorderColour = colour.Yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
protected override void OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
BorderThickness = 3;
|
BorderThickness = 3;
|
||||||
|
base.OnFocus(state);
|
||||||
return base.OnFocus(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFocusLost(InputState state)
|
protected override void OnFocusLost(InputState state)
|
||||||
|
@ -5,18 +5,21 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Transforms;
|
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class TwoLayerButton : ClickableContainer
|
public class TwoLayerButton : ClickableContainer
|
||||||
{
|
{
|
||||||
private readonly TextAwesome icon;
|
private readonly BouncingIcon bouncingIcon;
|
||||||
|
|
||||||
public Box IconLayer;
|
public Box IconLayer;
|
||||||
public Box TextLayer;
|
public Box TextLayer;
|
||||||
@ -95,11 +98,10 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon = new TextAwesome
|
bouncingIcon = new BouncingIcon
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
TextSize = 25,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -146,7 +148,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
icon.Icon = value;
|
bouncingIcon.Icon = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,58 +164,20 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
icon.ClearTransforms();
|
|
||||||
|
|
||||||
ResizeTo(SIZE_EXTENDED, transform_time, EasingTypes.OutElastic);
|
ResizeTo(SIZE_EXTENDED, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
int duration = 0; //(int)(Game.Audio.BeatLength / 2);
|
|
||||||
if (duration == 0) duration = pulse_length;
|
|
||||||
|
|
||||||
IconLayer.FadeColour(HoverColour, transform_time, EasingTypes.OutElastic);
|
IconLayer.FadeColour(HoverColour, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
const double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
|
bouncingIcon.ScaleTo(1.1f, transform_time, EasingTypes.OutElastic);
|
||||||
double startTime = Time.Current + offset;
|
|
||||||
|
|
||||||
// basic pulse
|
|
||||||
icon.Transforms.Add(new TransformScale
|
|
||||||
{
|
|
||||||
StartValue = new Vector2(1.1f),
|
|
||||||
EndValue = Vector2.One,
|
|
||||||
StartTime = startTime,
|
|
||||||
EndTime = startTime + duration,
|
|
||||||
Easing = EasingTypes.Out,
|
|
||||||
LoopCount = -1,
|
|
||||||
LoopDelay = duration
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
icon.ClearTransforms();
|
|
||||||
|
|
||||||
ResizeTo(SIZE_RETRACTED, transform_time, EasingTypes.OutElastic);
|
ResizeTo(SIZE_RETRACTED, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
IconLayer.FadeColour(TextLayer.Colour, transform_time, EasingTypes.OutElastic);
|
IconLayer.FadeColour(TextLayer.Colour, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
int duration = 0; //(int)(Game.Audio.BeatLength);
|
bouncingIcon.ScaleTo(1, transform_time, EasingTypes.OutElastic);
|
||||||
if (duration == 0) duration = pulse_length * 2;
|
|
||||||
|
|
||||||
const double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
|
|
||||||
double startTime = Time.Current + offset;
|
|
||||||
|
|
||||||
// slow pulse
|
|
||||||
icon.Transforms.Add(new TransformScale
|
|
||||||
{
|
|
||||||
StartValue = new Vector2(1.1f),
|
|
||||||
EndValue = Vector2.One,
|
|
||||||
StartTime = startTime,
|
|
||||||
EndTime = startTime + duration,
|
|
||||||
Easing = EasingTypes.Out,
|
|
||||||
LoopCount = -1,
|
|
||||||
LoopDelay = duration
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
@ -239,5 +203,45 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
return base.OnClick(state);
|
return base.OnClick(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BouncingIcon : BeatSyncedContainer
|
||||||
|
{
|
||||||
|
private const double beat_in_time = 60;
|
||||||
|
|
||||||
|
private readonly TextAwesome icon;
|
||||||
|
|
||||||
|
public FontAwesome Icon { set { icon.Icon = value; } }
|
||||||
|
|
||||||
|
public BouncingIcon()
|
||||||
|
{
|
||||||
|
EarlyActivationMilliseconds = beat_in_time;
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
icon = new TextAwesome
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
TextSize = 25
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||||
|
{
|
||||||
|
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||||
|
|
||||||
|
var beatLength = timingPoint.BeatLength;
|
||||||
|
|
||||||
|
float amplitudeAdjust = Math.Min(1, 0.4f + amplitudes.Maximum);
|
||||||
|
|
||||||
|
if (beatIndex < 0) return;
|
||||||
|
|
||||||
|
icon.ScaleTo(1 - 0.1f * amplitudeAdjust, beat_in_time, EasingTypes.Out);
|
||||||
|
using (icon.BeginDelayedSequence(beat_in_time))
|
||||||
|
icon.ScaleTo(1, beatLength * 2, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -74,7 +74,7 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeMeterMaster.TriggerWheel(state);
|
volumeMeterMaster.TriggerOnWheel(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -255,6 +255,9 @@ namespace osu.Game
|
|||||||
settings.ToggleVisibility();
|
settings.ToggleVisibility();
|
||||||
return true;
|
return true;
|
||||||
case Key.D:
|
case Key.D:
|
||||||
|
if (state.Keyboard.ShiftPressed || state.Keyboard.AltPressed)
|
||||||
|
return false;
|
||||||
|
|
||||||
direct.ToggleVisibility();
|
direct.ToggleVisibility();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ namespace osu.Game
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Cursor = new MenuCursor(),
|
Cursor = new MenuCursor(),
|
||||||
new TooltipContainer(Cursor) { Depth = -1 },
|
new OsuTooltipContainer(Cursor) { Depth = -1 },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Chat
|
namespace osu.Game.Overlays.Chat
|
||||||
{
|
{
|
||||||
@ -23,6 +24,8 @@ namespace osu.Game.Overlays.Chat
|
|||||||
|
|
||||||
private const float shear_width = 10;
|
private const float shear_width = 10;
|
||||||
|
|
||||||
|
public readonly Bindable<bool> ChannelSelectorActive = new Bindable<bool>();
|
||||||
|
|
||||||
public ChatTabControl()
|
public ChatTabControl()
|
||||||
{
|
{
|
||||||
TabContainer.Margin = new MarginPadding { Left = 50 };
|
TabContainer.Margin = new MarginPadding { Left = 50 };
|
||||||
@ -37,6 +40,8 @@ namespace osu.Game.Overlays.Chat
|
|||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
Padding = new MarginPadding(10),
|
Padding = new MarginPadding(10),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddTabItem(new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }, ChannelSelectorActive));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ChannelTabItem : TabItem<Channel>
|
private class ChannelTabItem : TabItem<Channel>
|
||||||
@ -49,6 +54,7 @@ namespace osu.Game.Overlays.Chat
|
|||||||
private readonly SpriteText textBold;
|
private readonly SpriteText textBold;
|
||||||
private readonly Box box;
|
private readonly Box box;
|
||||||
private readonly Box highlightBox;
|
private readonly Box highlightBox;
|
||||||
|
private readonly TextAwesome icon;
|
||||||
|
|
||||||
public override bool Active
|
public override bool Active
|
||||||
{
|
{
|
||||||
@ -114,6 +120,11 @@ namespace osu.Game.Overlays.Chat
|
|||||||
backgroundHover = colours.Gray7;
|
backgroundHover = colours.Gray7;
|
||||||
|
|
||||||
highlightBox.Colour = colours.Yellow;
|
highlightBox.Colour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
updateState();
|
updateState();
|
||||||
}
|
}
|
||||||
@ -159,7 +170,7 @@ namespace osu.Game.Overlays.Chat
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new TextAwesome
|
icon = new TextAwesome
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.fa_hashtag,
|
Icon = FontAwesome.fa_hashtag,
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
@ -191,6 +202,40 @@ namespace osu.Game.Overlays.Chat
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ChannelSelectorTabItem : ChannelTabItem
|
||||||
|
{
|
||||||
|
public override bool Active
|
||||||
|
{
|
||||||
|
get { return base.Active; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
activeBindable.Value = value;
|
||||||
|
base.Active = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Bindable<bool> activeBindable;
|
||||||
|
|
||||||
|
public ChannelSelectorTabItem(Channel value, Bindable<bool> active) : base(value)
|
||||||
|
{
|
||||||
|
activeBindable = active;
|
||||||
|
Depth = float.MaxValue;
|
||||||
|
Width = 45;
|
||||||
|
|
||||||
|
icon.Alpha = 0;
|
||||||
|
|
||||||
|
text.TextSize = 45;
|
||||||
|
textBold.TextSize = 45;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private new void load(OsuColour colour)
|
||||||
|
{
|
||||||
|
backgroundInactive = colour.Gray2;
|
||||||
|
backgroundActive = colour.Gray3;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
@ -43,11 +44,15 @@ namespace osu.Game.Overlays.Chat
|
|||||||
channel.NewMessagesArrived += newMessagesArrived;
|
channel.NewMessagesArrived += newMessagesArrived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
newMessagesArrived(Channel.Messages);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
newMessagesArrived(Channel.Messages);
|
|
||||||
scrollToEnd();
|
scrollToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,13 +64,13 @@ namespace osu.Game.Overlays.Chat
|
|||||||
|
|
||||||
private void newMessagesArrived(IEnumerable<Message> newMessages)
|
private void newMessagesArrived(IEnumerable<Message> newMessages)
|
||||||
{
|
{
|
||||||
if (!IsLoaded) return;
|
|
||||||
|
|
||||||
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
|
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
|
||||||
|
|
||||||
//up to last Channel.MAX_HISTORY messages
|
//up to last Channel.MAX_HISTORY messages
|
||||||
flow.Add(displayMessages.Select(m => new ChatLine(m)));
|
flow.Add(displayMessages.Select(m => new ChatLine(m)));
|
||||||
|
|
||||||
|
if (!IsLoaded) return;
|
||||||
|
|
||||||
if (scroll.IsScrolledToEnd(10) || !flow.Children.Any())
|
if (scroll.IsScrolledToEnd(10) || !flow.Children.Any())
|
||||||
scrollToEnd();
|
scrollToEnd();
|
||||||
|
|
||||||
|
@ -135,17 +135,22 @@ namespace osu.Game.Overlays
|
|||||||
channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
|
channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double startDragChatHeight;
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state)
|
protected override bool OnDragStart(InputState state)
|
||||||
{
|
{
|
||||||
if (channelTabs.Hovering)
|
if (!channelTabs.Hovering)
|
||||||
return true;
|
|
||||||
|
|
||||||
return base.OnDragStart(state);
|
return base.OnDragStart(state);
|
||||||
|
|
||||||
|
startDragChatHeight = chatHeight.Value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
chatHeight.Value = Height - state.Mouse.Delta.Y / Parent.DrawSize.Y;
|
Trace.Assert(state.Mouse.PositionMouseDown != null);
|
||||||
|
|
||||||
|
chatHeight.Value = startDragChatHeight - (state.Mouse.Position.Y - state.Mouse.PositionMouseDown.Value.Y) / Parent.DrawSize.Y;
|
||||||
return base.OnDrag(state);
|
return base.OnDrag(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,11 +167,15 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
public override bool AcceptsFocus => true;
|
||||||
|
|
||||||
|
protected override bool OnClick(InputState state) => true;
|
||||||
|
|
||||||
|
protected override void OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
||||||
inputTextBox.TriggerFocus();
|
InputManager.ChangeFocus(inputTextBox);
|
||||||
return false;
|
base.OnFocus(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
@ -255,20 +264,32 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
if (currentChannel == value) return;
|
if (currentChannel == value) return;
|
||||||
|
|
||||||
if (currentChannel != null)
|
if (channelTabs.ChannelSelectorActive) return;
|
||||||
currentChannelContainer.Clear(false);
|
|
||||||
|
|
||||||
currentChannel = value;
|
currentChannel = value;
|
||||||
|
|
||||||
|
inputTextBox.Current.Disabled = currentChannel.ReadOnly;
|
||||||
|
channelTabs.Current.Value = value;
|
||||||
|
|
||||||
var loaded = loadedChannels.Find(d => d.Channel == value);
|
var loaded = loadedChannels.Find(d => d.Channel == value);
|
||||||
if (loaded == null)
|
if (loaded == null)
|
||||||
loadedChannels.Add(loaded = new DrawableChannel(currentChannel));
|
{
|
||||||
|
currentChannelContainer.FadeOut(500, EasingTypes.OutQuint);
|
||||||
inputTextBox.Current.Disabled = currentChannel.ReadOnly;
|
|
||||||
|
|
||||||
|
loaded = new DrawableChannel(currentChannel);
|
||||||
|
loadedChannels.Add(loaded);
|
||||||
|
LoadComponentAsync(loaded, l =>
|
||||||
|
{
|
||||||
|
currentChannelContainer.Clear(false);
|
||||||
|
currentChannelContainer.Add(l);
|
||||||
|
currentChannelContainer.FadeIn(500, EasingTypes.OutQuint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentChannelContainer.Clear(false);
|
||||||
currentChannelContainer.Add(loaded);
|
currentChannelContainer.Add(loaded);
|
||||||
|
}
|
||||||
channelTabs.Current.Value = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
private void pressButtonAtIndex(int index)
|
private void pressButtonAtIndex(int index)
|
||||||
{
|
{
|
||||||
if (index < Buttons.Count())
|
if (index < Buttons.Count())
|
||||||
Buttons.Skip(index).First().TriggerClick();
|
Buttons.Skip(index).First().TriggerOnClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
|
|
||||||
if (args.Key == Key.Enter)
|
if (args.Key == Key.Enter)
|
||||||
{
|
{
|
||||||
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerClick();
|
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Overlays
|
|||||||
new ScrollContainer
|
new ScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ScrollDraggerVisible = false,
|
ScrollbarVisible = false,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
@ -187,10 +187,14 @@ namespace osu.Game.Overlays
|
|||||||
panels.Children = BeatmapSets.Select(b => displayStyle == PanelDisplayStyle.Grid ? (DirectPanel)new DirectGridPanel(b) { Width = 400 } : new DirectListPanel(b));
|
panels.Children = BeatmapSets.Select(b => displayStyle == PanelDisplayStyle.Grid ? (DirectPanel)new DirectGridPanel(b) { Width = 400 } : new DirectListPanel(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
public override bool AcceptsFocus => true;
|
||||||
|
|
||||||
|
protected override bool OnClick(InputState state) => true;
|
||||||
|
|
||||||
|
protected override void OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
filter.Search.TriggerFocus();
|
InputManager.ChangeFocus(filter.Search);
|
||||||
return false;
|
base.OnFocus(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Overlays
|
|||||||
settingsSection.Bounding = true;
|
settingsSection.Bounding = true;
|
||||||
FadeIn(transition_time, EasingTypes.OutQuint);
|
FadeIn(transition_time, EasingTypes.OutQuint);
|
||||||
|
|
||||||
settingsSection.TriggerFocus();
|
InputManager.ChangeFocus(settingsSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
|
@ -16,7 +16,7 @@ using osu.Game.Rulesets.Mods;
|
|||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Graphics;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
@ -27,6 +27,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
public class ModButton : ModButtonEmpty, IHasTooltip
|
public class ModButton : ModButtonEmpty, IHasTooltip
|
||||||
{
|
{
|
||||||
private ModIcon foregroundIcon;
|
private ModIcon foregroundIcon;
|
||||||
|
private ModIcon backgroundIcon;
|
||||||
private readonly SpriteText text;
|
private readonly SpriteText text;
|
||||||
private readonly Container<ModIcon> iconsContainer;
|
private readonly Container<ModIcon> iconsContainer;
|
||||||
private SampleChannel sampleOn, sampleOff;
|
private SampleChannel sampleOn, sampleOff;
|
||||||
@ -35,38 +36,67 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
public string TooltipText => (SelectedMod?.Description ?? Mods.FirstOrDefault()?.Description) ?? string.Empty;
|
public string TooltipText => (SelectedMod?.Description ?? Mods.FirstOrDefault()?.Description) ?? string.Empty;
|
||||||
|
|
||||||
private int _selectedIndex = -1;
|
private const EasingTypes mod_switch_easing = EasingTypes.InOutSine;
|
||||||
private int selectedIndex
|
private const double mod_switch_duration = 120;
|
||||||
|
|
||||||
|
// A selected index of -1 means not selected.
|
||||||
|
private int selectedIndex = -1;
|
||||||
|
|
||||||
|
protected int SelectedIndex
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _selectedIndex;
|
return selectedIndex;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == _selectedIndex) return;
|
if (value == selectedIndex) return;
|
||||||
_selectedIndex = value;
|
|
||||||
|
int direction = value < selectedIndex ? -1 : 1;
|
||||||
|
bool beforeSelected = Selected;
|
||||||
|
|
||||||
|
Mod modBefore = SelectedMod ?? Mods[0];
|
||||||
|
|
||||||
if (value >= Mods.Length)
|
if (value >= Mods.Length)
|
||||||
{
|
selectedIndex = -1;
|
||||||
_selectedIndex = -1;
|
else if (value < -1)
|
||||||
}
|
selectedIndex = Mods.Length - 1;
|
||||||
else if (value <= -2)
|
else
|
||||||
{
|
selectedIndex = value;
|
||||||
_selectedIndex = Mods.Length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Mod modAfter = SelectedMod ?? Mods[0];
|
||||||
|
|
||||||
|
if (beforeSelected != Selected)
|
||||||
|
{
|
||||||
iconsContainer.RotateTo(Selected ? 5f : 0f, 300, EasingTypes.OutElastic);
|
iconsContainer.RotateTo(Selected ? 5f : 0f, 300, EasingTypes.OutElastic);
|
||||||
iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, EasingTypes.OutElastic);
|
iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, EasingTypes.OutElastic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modBefore != modAfter)
|
||||||
|
{
|
||||||
|
const float rotate_angle = 16;
|
||||||
|
|
||||||
|
foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing);
|
||||||
|
backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing);
|
||||||
|
|
||||||
|
backgroundIcon.Icon = modAfter.Icon;
|
||||||
|
using (iconsContainer.BeginDelayedSequence(mod_switch_duration, true))
|
||||||
|
{
|
||||||
|
foregroundIcon.RotateTo(-rotate_angle * direction);
|
||||||
|
foregroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
|
||||||
|
|
||||||
|
backgroundIcon.RotateTo(rotate_angle * direction);
|
||||||
|
backgroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
|
||||||
|
|
||||||
|
iconsContainer.Schedule(() => displayMod(modAfter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foregroundIcon.Highlighted = Selected;
|
foregroundIcon.Highlighted = Selected;
|
||||||
|
|
||||||
if (mod != null)
|
|
||||||
displayMod(SelectedMod ?? Mods[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Selected => selectedIndex != -1;
|
public bool Selected => SelectedIndex != -1;
|
||||||
|
|
||||||
|
|
||||||
private Color4 selectedColour;
|
private Color4 selectedColour;
|
||||||
public Color4 SelectedColour
|
public Color4 SelectedColour
|
||||||
@ -117,7 +147,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
// the mods from Mod, only multiple if Mod is a MultiMod
|
// the mods from Mod, only multiple if Mod is a MultiMod
|
||||||
|
|
||||||
public override Mod SelectedMod => Mods.ElementAtOrDefault(selectedIndex);
|
public override Mod SelectedMod => Mods.ElementAtOrDefault(SelectedIndex);
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio)
|
||||||
@ -142,23 +172,25 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
public void SelectNext()
|
public void SelectNext()
|
||||||
{
|
{
|
||||||
(++selectedIndex == -1 ? sampleOff : sampleOn).Play();
|
(++SelectedIndex == -1 ? sampleOff : sampleOn).Play();
|
||||||
Action?.Invoke(SelectedMod);
|
Action?.Invoke(SelectedMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectPrevious()
|
public void SelectPrevious()
|
||||||
{
|
{
|
||||||
(--selectedIndex == -1 ? sampleOff : sampleOn).Play();
|
(--SelectedIndex == -1 ? sampleOff : sampleOn).Play();
|
||||||
Action?.Invoke(SelectedMod);
|
Action?.Invoke(SelectedMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deselect()
|
public void Deselect()
|
||||||
{
|
{
|
||||||
selectedIndex = -1;
|
SelectedIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayMod(Mod mod)
|
private void displayMod(Mod mod)
|
||||||
{
|
{
|
||||||
|
if (backgroundIcon != null)
|
||||||
|
backgroundIcon.Icon = foregroundIcon.Icon;
|
||||||
foregroundIcon.Icon = mod.Icon;
|
foregroundIcon.Icon = mod.Icon;
|
||||||
text.Text = mod.Name;
|
text.Text = mod.Name;
|
||||||
}
|
}
|
||||||
@ -170,17 +202,17 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
iconsContainer.Add(new[]
|
iconsContainer.Add(new[]
|
||||||
{
|
{
|
||||||
new ModIcon(Mods[0])
|
backgroundIcon = new ModIcon(Mods[1])
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.BottomRight,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.BottomRight,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Position = new Vector2(1.5f),
|
Position = new Vector2(1.5f),
|
||||||
},
|
},
|
||||||
foregroundIcon = new ModIcon(Mods[0])
|
foregroundIcon = new ModIcon(Mods[0])
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.BottomRight,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.BottomRight,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Position = new Vector2(-1.5f),
|
Position = new Vector2(-1.5f),
|
||||||
},
|
},
|
||||||
|
73
osu.Game/Overlays/Music/CollectionsDropdown.cs
Normal file
73
osu.Game/Overlays/Music/CollectionsDropdown.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// 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.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Music
|
||||||
|
{
|
||||||
|
public class CollectionsDropdown<T> : OsuDropdown<T>
|
||||||
|
{
|
||||||
|
protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
|
||||||
|
protected override Menu CreateMenu() => new CollectionsMenu();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
AccentColour = colours.Gray6;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CollectionsHeader : OsuDropdownHeader
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
BackgroundColour = colours.Gray4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollectionsHeader()
|
||||||
|
{
|
||||||
|
CornerRadius = 5;
|
||||||
|
Height = 30;
|
||||||
|
Icon.TextSize = 14;
|
||||||
|
Icon.Margin = new MarginPadding(0);
|
||||||
|
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
|
||||||
|
EdgeEffect = new EdgeEffect
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Colour = Color4.Black.Opacity(0.3f),
|
||||||
|
Radius = 3,
|
||||||
|
Offset = new Vector2(0f, 1f),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CollectionsMenu : OsuMenu
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
Background.Colour = colours.Gray4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollectionsMenu()
|
||||||
|
{
|
||||||
|
CornerRadius = 5;
|
||||||
|
EdgeEffect = new EdgeEffect
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Colour = Color4.Black.Opacity(0.3f),
|
||||||
|
Radius = 3,
|
||||||
|
Offset = new Vector2(0f, 1f),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,10 +3,8 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -74,63 +72,5 @@ namespace osu.Game.Overlays.Music
|
|||||||
backgroundColour = colours.Gray2;
|
backgroundColour = colours.Gray2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CollectionsDropdown<T> : OsuDropdown<T>
|
|
||||||
{
|
|
||||||
protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
|
|
||||||
protected override Menu CreateMenu() => new CollectionsMenu();
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
AccentColour = colours.Gray6;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CollectionsHeader : OsuDropdownHeader
|
|
||||||
{
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
BackgroundColour = colours.Gray4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CollectionsHeader()
|
|
||||||
{
|
|
||||||
CornerRadius = 5;
|
|
||||||
Height = 30;
|
|
||||||
Icon.TextSize = 14;
|
|
||||||
Icon.Margin = new MarginPadding(0);
|
|
||||||
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
|
|
||||||
EdgeEffect = new EdgeEffect
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Colour = Color4.Black.Opacity(0.3f),
|
|
||||||
Radius = 3,
|
|
||||||
Offset = new Vector2(0f, 1f),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CollectionsMenu : OsuMenu
|
|
||||||
{
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
Background.Colour = colours.Gray4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CollectionsMenu()
|
|
||||||
{
|
|
||||||
CornerRadius = 5;
|
|
||||||
EdgeEffect = new EdgeEffect
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Colour = Color4.Black.Opacity(0.3f),
|
|
||||||
Radius = 3,
|
|
||||||
Offset = new Vector2(0f, 1f),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
|
|
||||||
private bool matching = true;
|
private bool matching = true;
|
||||||
|
|
||||||
public bool MatchingCurrentFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingCurrentFilter)?.BeatmapSetInfo;
|
public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
|
||||||
|
|
||||||
private void itemSelected(BeatmapSetInfo b)
|
private void itemSelected(BeatmapSetInfo b)
|
||||||
{
|
{
|
||||||
@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
||||||
{
|
{
|
||||||
public string[] FilterTerms => new string[] { };
|
public string[] FilterTerms => new string[] { };
|
||||||
public bool MatchingCurrentFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Graphics;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Music
|
namespace osu.Game.Overlays.Music
|
||||||
{
|
{
|
||||||
@ -35,10 +36,12 @@ namespace osu.Game.Overlays.Music
|
|||||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
public IEnumerable<BeatmapSetInfo> BeatmapSets;
|
public IEnumerable<BeatmapSetInfo> BeatmapSets;
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours)
|
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours, UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
this.beatmaps = beatmaps;
|
this.beatmaps = beatmaps;
|
||||||
trackManager = game.Audio.Track;
|
trackManager = game.Audio.Track;
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
filter.Search.HoldFocus = true;
|
filter.Search.HoldFocus = true;
|
||||||
Schedule(() => filter.Search.TriggerFocus());
|
Schedule(() => inputManager.ChangeFocus(filter.Search));
|
||||||
|
|
||||||
ResizeTo(new Vector2(1, playlist_height), transition_duration, EasingTypes.OutQuint);
|
ResizeTo(new Vector2(1, playlist_height), transition_duration, EasingTypes.OutQuint);
|
||||||
FadeIn(transition_duration, EasingTypes.OutQuint);
|
FadeIn(transition_duration, EasingTypes.OutQuint);
|
||||||
|
@ -22,6 +22,7 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Overlays.Music;
|
using osu.Game.Overlays.Music;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
@ -38,8 +39,8 @@ namespace osu.Game.Overlays
|
|||||||
private Drawable currentBackground;
|
private Drawable currentBackground;
|
||||||
private DragBar progressBar;
|
private DragBar progressBar;
|
||||||
|
|
||||||
private Button playButton;
|
private IconButton playButton;
|
||||||
private Button playlistButton;
|
private IconButton playlistButton;
|
||||||
|
|
||||||
private SpriteText title, artist;
|
private SpriteText title, artist;
|
||||||
|
|
||||||
@ -143,7 +144,7 @@ namespace osu.Game.Overlays
|
|||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer<Button>
|
new FillFlowContainer<IconButton>
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
@ -152,26 +153,26 @@ namespace osu.Game.Overlays
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Button
|
new IconButton
|
||||||
{
|
{
|
||||||
Action = prev,
|
Action = prev,
|
||||||
Icon = FontAwesome.fa_step_backward,
|
Icon = FontAwesome.fa_step_backward,
|
||||||
},
|
},
|
||||||
playButton = new Button
|
playButton = new IconButton
|
||||||
{
|
{
|
||||||
Scale = new Vector2(1.4f),
|
Scale = new Vector2(1.4f),
|
||||||
IconScale = new Vector2(1.4f),
|
IconScale = new Vector2(1.4f),
|
||||||
Action = play,
|
Action = play,
|
||||||
Icon = FontAwesome.fa_play_circle_o,
|
Icon = FontAwesome.fa_play_circle_o,
|
||||||
},
|
},
|
||||||
new Button
|
new IconButton
|
||||||
{
|
{
|
||||||
Action = next,
|
Action = next,
|
||||||
Icon = FontAwesome.fa_step_forward,
|
Icon = FontAwesome.fa_step_forward,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
playlistButton = new Button
|
playlistButton = new IconButton
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
@ -266,9 +267,11 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
progressBar.IsEnabled = beatmap != null;
|
progressBar.IsEnabled = beatmap != null;
|
||||||
|
|
||||||
bool audioEquals = beatmapBacking.Value?.BeatmapInfo?.AudioEquals(current?.BeatmapInfo) ?? false;
|
TransformDirection direction = TransformDirection.None;
|
||||||
|
|
||||||
TransformDirection direction;
|
if (current != null)
|
||||||
|
{
|
||||||
|
bool audioEquals = beatmapBacking.Value?.BeatmapInfo?.AudioEquals(current.BeatmapInfo) ?? false;
|
||||||
|
|
||||||
if (audioEquals)
|
if (audioEquals)
|
||||||
direction = TransformDirection.None;
|
direction = TransformDirection.None;
|
||||||
@ -280,11 +283,12 @@ namespace osu.Game.Overlays
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//figure out the best direction based on order in playlist.
|
//figure out the best direction based on order in playlist.
|
||||||
var last = current == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
|
var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
|
||||||
var next = beatmapBacking.Value == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmapBacking.Value.BeatmapSetInfo.ID).Count();
|
var next = beatmapBacking.Value == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmapBacking.Value.BeatmapSetInfo.ID).Count();
|
||||||
|
|
||||||
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
current = beatmapBacking.Value;
|
current = beatmapBacking.Value;
|
||||||
|
|
||||||
@ -412,105 +416,5 @@ namespace osu.Game.Overlays
|
|||||||
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Button : ClickableContainer
|
|
||||||
{
|
|
||||||
private readonly TextAwesome icon;
|
|
||||||
private readonly Box hover;
|
|
||||||
private readonly Container content;
|
|
||||||
|
|
||||||
public FontAwesome Icon
|
|
||||||
{
|
|
||||||
get { return icon.Icon; }
|
|
||||||
set { icon.Icon = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private const float button_size = 30;
|
|
||||||
private Color4 flashColour;
|
|
||||||
|
|
||||||
public Vector2 IconScale
|
|
||||||
{
|
|
||||||
get { return icon.Scale; }
|
|
||||||
set { icon.Scale = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Button()
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
Origin = Anchor.Centre;
|
|
||||||
Anchor = Anchor.Centre;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
content = new Container
|
|
||||||
{
|
|
||||||
Size = new Vector2(button_size),
|
|
||||||
CornerRadius = 5,
|
|
||||||
Masking = true,
|
|
||||||
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
EdgeEffect = new EdgeEffect
|
|
||||||
{
|
|
||||||
Colour = Color4.Black.Opacity(0.04f),
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Radius = 5,
|
|
||||||
},
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
hover = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0,
|
|
||||||
},
|
|
||||||
icon = new TextAwesome
|
|
||||||
{
|
|
||||||
TextSize = 18,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Anchor = Anchor.Centre
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
hover.Colour = colours.Yellow.Opacity(0.6f);
|
|
||||||
flashColour = colours.Yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
|
||||||
{
|
|
||||||
hover.FadeIn(500, EasingTypes.OutQuint);
|
|
||||||
return base.OnHover(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
|
||||||
{
|
|
||||||
hover.FadeOut(500, EasingTypes.OutQuint);
|
|
||||||
base.OnHoverLost(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnClick(InputState state)
|
|
||||||
{
|
|
||||||
hover.FlashColour(flashColour, 800, EasingTypes.OutQuint);
|
|
||||||
return base.OnClick(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
|
||||||
{
|
|
||||||
content.ScaleTo(0.75f, 2000, EasingTypes.OutQuint);
|
|
||||||
return base.OnMouseDown(state, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
|
||||||
{
|
|
||||||
content.ScaleTo(1, 1000, EasingTypes.OutElastic);
|
|
||||||
return base.OnMouseUp(state, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
LabelText = "up to",
|
LabelText = "up to",
|
||||||
Bindable = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum)
|
Bindable = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum)
|
||||||
},
|
},
|
||||||
|
new SettingsEnumDropdown<SelectionRandomType>
|
||||||
|
{
|
||||||
|
LabelText = "Random beatmap selection",
|
||||||
|
Bindable = config.GetBindable<SelectionRandomType>(OsuSetting.SelectionRandomType),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +51,12 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
Spacing = new Vector2(0f, 5f);
|
Spacing = new Vector2(0f, 5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(OsuColour colours, APIAccess api)
|
private void load(OsuColour colours, APIAccess api, UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
this.colours = colours;
|
this.colours = colours;
|
||||||
api?.Register(this);
|
api?.Register(this);
|
||||||
}
|
}
|
||||||
@ -160,13 +163,17 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
form?.TriggerFocus();
|
if (form != null) inputManager.ChangeFocus(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
public override bool AcceptsFocus => true;
|
||||||
|
|
||||||
|
protected override bool OnClick(InputState state) => true;
|
||||||
|
|
||||||
|
protected override void OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
form?.TriggerFocus();
|
if (form != null) inputManager.ChangeFocus(form);
|
||||||
return base.OnFocus(state);
|
base.OnFocus(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LoginForm : FillFlowContainer
|
private class LoginForm : FillFlowContainer
|
||||||
@ -174,6 +181,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
private TextBox username;
|
private TextBox username;
|
||||||
private TextBox password;
|
private TextBox password;
|
||||||
private APIAccess api;
|
private APIAccess api;
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
private void performLogin()
|
private void performLogin()
|
||||||
{
|
{
|
||||||
@ -182,8 +190,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(APIAccess api, OsuConfigManager config)
|
private void load(APIAccess api, OsuConfigManager config, UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
this.api = api;
|
this.api = api;
|
||||||
Direction = FillDirection.Vertical;
|
Direction = FillDirection.Vertical;
|
||||||
Spacing = new Vector2(0, 5);
|
Spacing = new Vector2(0, 5);
|
||||||
@ -230,17 +239,13 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
public override bool AcceptsFocus => true;
|
||||||
{
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(username.Text))
|
|
||||||
username.TriggerFocus();
|
|
||||||
else
|
|
||||||
password.TriggerFocus();
|
|
||||||
});
|
|
||||||
|
|
||||||
return base.OnFocus(state);
|
protected override bool OnClick(InputState state) => true;
|
||||||
|
|
||||||
|
protected override void OnFocus(InputState state)
|
||||||
|
{
|
||||||
|
Schedule(() => { inputManager.ChangeFocus(string.IsNullOrEmpty(username.Text) ? username : password); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,8 +345,8 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
{
|
{
|
||||||
public UserDropdownMenuItem(string text, UserAction current) : base(text, current)
|
public UserDropdownMenuItem(string text, UserAction current) : base(text, current)
|
||||||
{
|
{
|
||||||
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = UserDropdownHeader.LABEL_LEFT_MARGIN, Right = 5 };
|
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 };
|
||||||
Chevron.Margin = new MarginPadding { Left = 2, Right = 3 };
|
Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 };
|
||||||
CornerRadius = 5;
|
CornerRadius = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,31 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
{
|
{
|
||||||
protected override string Header => "Mouse";
|
protected override string Header => "Mouse";
|
||||||
|
|
||||||
|
private readonly BindableBool rawInputToggle = new BindableBool();
|
||||||
|
private Bindable<string> activeInputHandlers;
|
||||||
|
private SensitivitySetting sensitivity;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager osuConfig, FrameworkConfigManager config)
|
private void load(OsuConfigManager osuConfig, FrameworkConfigManager config)
|
||||||
{
|
{
|
||||||
|
activeInputHandlers = config.GetBindable<string>(FrameworkSetting.ActiveInputHandlers);
|
||||||
|
rawInputToggle.Value = activeInputHandlers.Value.Contains("Raw");
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
new SettingsCheckbox
|
||||||
|
{
|
||||||
|
LabelText = "Raw Input",
|
||||||
|
Bindable = rawInputToggle
|
||||||
|
},
|
||||||
|
sensitivity = new SensitivitySetting
|
||||||
|
{
|
||||||
|
LabelText = "Cursor Sensitivity",
|
||||||
|
Bindable = config.GetBindable<double>(FrameworkSetting.CursorSensitivity)
|
||||||
|
},
|
||||||
new SettingsEnumDropdown<ConfineMouseMode>
|
new SettingsEnumDropdown<ConfineMouseMode>
|
||||||
{
|
{
|
||||||
LabelText = "Confine mouse cursor",
|
LabelText = "Confine mouse cursor to window",
|
||||||
Bindable = config.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode),
|
Bindable = config.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode),
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
@ -35,11 +52,82 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
Bindable = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons)
|
Bindable = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rawInputToggle.ValueChanged += enabled =>
|
||||||
|
{
|
||||||
|
// this is temporary until we support per-handler settings.
|
||||||
|
const string raw_mouse_handler = @"OpenTKRawMouseHandler";
|
||||||
|
const string standard_mouse_handler = @"OpenTKMouseHandler";
|
||||||
|
|
||||||
|
activeInputHandlers.Value = enabled ?
|
||||||
|
activeInputHandlers.Value.Replace(standard_mouse_handler, raw_mouse_handler) :
|
||||||
|
activeInputHandlers.Value.Replace(raw_mouse_handler, standard_mouse_handler);
|
||||||
|
|
||||||
|
sensitivity.Bindable.Disabled = !enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
rawInputToggle.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SensitivitySetting : SettingsSlider<double, SensitivitySlider>
|
||||||
|
{
|
||||||
|
public override Bindable<double> Bindable
|
||||||
|
{
|
||||||
|
get { return ((SensitivitySlider)Control).Sensitivity; }
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BindableDouble doubleValue = (BindableDouble)value;
|
||||||
|
|
||||||
|
// create a second layer of bindable so we can only handle state changes when not being dragged.
|
||||||
|
((SensitivitySlider)Control).Sensitivity = doubleValue;
|
||||||
|
|
||||||
|
// this bindable will still act as the "interactive" bindable displayed during a drag.
|
||||||
|
base.Bindable = new BindableDouble(doubleValue.Value)
|
||||||
|
{
|
||||||
|
MinValue = doubleValue.MinValue,
|
||||||
|
MaxValue = doubleValue.MaxValue
|
||||||
|
};
|
||||||
|
|
||||||
|
// one-way binding to update the sliderbar with changes from external actions.
|
||||||
|
doubleValue.DisabledChanged += disabled => base.Bindable.Disabled = disabled;
|
||||||
|
doubleValue.ValueChanged += newValue => base.Bindable.Value = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SensitivitySlider : OsuSliderBar<double>
|
private class SensitivitySlider : OsuSliderBar<double>
|
||||||
{
|
{
|
||||||
public override string TooltipText => Current.Value.ToString(@"0.##x");
|
public Bindable<double> Sensitivity;
|
||||||
|
|
||||||
|
public SensitivitySlider()
|
||||||
|
{
|
||||||
|
KeyboardStep = 0.01f;
|
||||||
|
|
||||||
|
Current.ValueChanged += newValue =>
|
||||||
|
{
|
||||||
|
if (!isDragging && Sensitivity != null)
|
||||||
|
Sensitivity.Value = newValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isDragging;
|
||||||
|
|
||||||
|
protected override bool OnDragStart(InputState state)
|
||||||
|
{
|
||||||
|
isDragging = true;
|
||||||
|
return base.OnDragStart(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnDragEnd(InputState state)
|
||||||
|
{
|
||||||
|
isDragging = false;
|
||||||
|
Current.TriggerChange();
|
||||||
|
|
||||||
|
return base.OnDragEnd(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string TooltipText => Current.Disabled ? "Enable raw input to adjust sensitivity" : Current.Value.ToString(@"0.##x");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
// hold a reference to the provided bindable so we don't have to in every settings section.
|
// hold a reference to the provided bindable so we don't have to in every settings section.
|
||||||
private Bindable<T> bindable;
|
private Bindable<T> bindable;
|
||||||
|
|
||||||
public Bindable<T> Bindable
|
public virtual Bindable<T> Bindable
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -55,7 +55,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
public string[] FilterTerms => new[] { LabelText };
|
public string[] FilterTerms => new[] { LabelText };
|
||||||
|
|
||||||
public bool MatchingCurrentFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
||||||
public string[] FilterTerms => new[] { Header };
|
public string[] FilterTerms => new[] { Header };
|
||||||
public bool MatchingCurrentFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
||||||
public string[] FilterTerms => new[] { Header };
|
public string[] FilterTerms => new[] { Header };
|
||||||
public bool MatchingCurrentFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -134,13 +134,18 @@ namespace osu.Game.Overlays
|
|||||||
FadeTo(0, TRANSITION_LENGTH / 2);
|
FadeTo(0, TRANSITION_LENGTH / 2);
|
||||||
|
|
||||||
searchTextBox.HoldFocus = false;
|
searchTextBox.HoldFocus = false;
|
||||||
searchTextBox.TriggerFocusLost();
|
if (searchTextBox.HasFocus)
|
||||||
|
InputManager.ChangeFocus(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
public override bool AcceptsFocus => true;
|
||||||
|
|
||||||
|
protected override bool OnClick(InputState state) => true;
|
||||||
|
|
||||||
|
protected override void OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
searchTextBox.TriggerFocus(state);
|
InputManager.ChangeFocus(searchTextBox);
|
||||||
return false;
|
base.OnFocus(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SettingsSectionsContainer : SectionsContainer
|
private class SettingsSectionsContainer : SectionsContainer
|
||||||
@ -158,7 +163,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
public SettingsSectionsContainer()
|
public SettingsSectionsContainer()
|
||||||
{
|
{
|
||||||
ScrollContainer.ScrollDraggerVisible = false;
|
ScrollContainer.ScrollbarVisible = false;
|
||||||
Add(headerBackground = new Box
|
Add(headerBackground = new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
|
25
osu.Game/Rulesets/Mods/ModDaycore.cs
Normal file
25
osu.Game/Rulesets/Mods/ModDaycore.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.Audio;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
{
|
||||||
|
public abstract class ModDaycore : ModHalfTime
|
||||||
|
{
|
||||||
|
public override string Name => "Daycore";
|
||||||
|
public override FontAwesome Icon => FontAwesome.fa_question;
|
||||||
|
public override string Description => "whoaaaaa";
|
||||||
|
|
||||||
|
public override void ApplyToClock(IAdjustableClock clock)
|
||||||
|
{
|
||||||
|
var pitchAdjust = clock as IHasPitchAdjust;
|
||||||
|
if (pitchAdjust != null)
|
||||||
|
pitchAdjust.PitchAdjust = 0.75;
|
||||||
|
else
|
||||||
|
base.ApplyToClock(clock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
public void ApplyToClock(IAdjustableClock clock)
|
public virtual void ApplyToClock(IAdjustableClock clock)
|
||||||
{
|
{
|
||||||
clock.Rate = 0.75;
|
clock.Rate = 0.75;
|
||||||
}
|
}
|
||||||
|
@ -15,28 +15,51 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Drawables
|
namespace osu.Game.Rulesets.Objects.Drawables
|
||||||
{
|
{
|
||||||
public abstract class DrawableHitObject<TObject, TJudgement> : Container
|
public abstract class DrawableHitObject : Container
|
||||||
where TObject : HitObject
|
|
||||||
where TJudgement : Judgement
|
|
||||||
{
|
{
|
||||||
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
|
public readonly HitObject HitObject;
|
||||||
|
|
||||||
public TObject HitObject;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The colour used for various elements of this DrawableHitObject.
|
/// The colour used for various elements of this DrawableHitObject.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Color4 AccentColour { get; set; }
|
public virtual Color4 AccentColour { get; set; }
|
||||||
|
|
||||||
|
protected DrawableHitObject(HitObject hitObject)
|
||||||
|
{
|
||||||
|
HitObject = hitObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
||||||
|
where TObject : HitObject
|
||||||
|
{
|
||||||
|
public new readonly TObject HitObject;
|
||||||
|
|
||||||
|
protected DrawableHitObject(TObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
HitObject = hitObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class DrawableHitObject<TObject, TJudgement> : DrawableHitObject<TObject>
|
||||||
|
where TObject : HitObject
|
||||||
|
where TJudgement : Judgement
|
||||||
|
{
|
||||||
|
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
|
||||||
|
|
||||||
public override bool HandleInput => Interactive;
|
public override bool HandleInput => Interactive;
|
||||||
|
|
||||||
public bool Interactive = true;
|
public bool Interactive = true;
|
||||||
|
|
||||||
public TJudgement Judgement;
|
public TJudgement Judgement;
|
||||||
|
|
||||||
protected abstract TJudgement CreateJudgement();
|
protected List<SampleChannel> Samples = new List<SampleChannel>();
|
||||||
|
|
||||||
protected abstract void UpdateState(ArmedState state);
|
protected DrawableHitObject(TObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private ArmedState state;
|
private ArmedState state;
|
||||||
public ArmedState State
|
public ArmedState State
|
||||||
@ -59,8 +82,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<SampleChannel> Samples = new List<SampleChannel>();
|
|
||||||
|
|
||||||
protected void PlaySamples()
|
protected void PlaySamples()
|
||||||
{
|
{
|
||||||
Samples.ForEach(s => s?.Play());
|
Samples.ForEach(s => s?.Play());
|
||||||
@ -79,11 +100,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Judged => (Judgement?.Result ?? HitResult.None) != HitResult.None && (NestedHitObjects?.All(h => h.Judged) ?? true);
|
public bool Judged => (Judgement?.Result ?? HitResult.None) != HitResult.None && (NestedHitObjects?.All(h => h.Judged) ?? true);
|
||||||
|
|
||||||
protected DrawableHitObject(TObject hitObject)
|
|
||||||
{
|
|
||||||
HitObject = hitObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Process a hit of this hitobject. Carries out judgement.
|
/// Process a hit of this hitobject. Carries out judgement.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -176,5 +192,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
h.OnJudgement += d => OnJudgement?.Invoke(d);
|
h.OnJudgement += d => OnJudgement?.Invoke(d);
|
||||||
nestedHitObjects.Add(h);
|
nestedHitObjects.Add(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract TJudgement CreateJudgement();
|
||||||
|
protected abstract void UpdateState(ArmedState state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time at which the HitObject starts.
|
/// The time at which the HitObject starts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double StartTime;
|
public virtual double StartTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The samples to be played when this hit object is hit.
|
/// The samples to be played when this hit object is hit.
|
||||||
|
55
osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs
Normal file
55
osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two hit objects by their start time, falling back to creation order if their start time is equal.
|
||||||
|
/// </summary>
|
||||||
|
public class HitObjectStartTimeComparer : Drawable.CreationOrderDepthComparer
|
||||||
|
{
|
||||||
|
public override int Compare(Drawable x, Drawable y)
|
||||||
|
{
|
||||||
|
var hitObjectX = x as DrawableHitObject;
|
||||||
|
var hitObjectY = y as DrawableHitObject;
|
||||||
|
|
||||||
|
// If either of the two drawables are not hit objects, fall back to the base comparer
|
||||||
|
if (hitObjectX?.HitObject == null || hitObjectY?.HitObject == null)
|
||||||
|
return base.Compare(x, y);
|
||||||
|
|
||||||
|
// Compare by start time
|
||||||
|
int i = hitObjectX.HitObject.StartTime.CompareTo(hitObjectY.HitObject.StartTime);
|
||||||
|
if (i != 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return base.Compare(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two hit objects by their start time, falling back to creation order if their start time is equal.
|
||||||
|
/// This will compare the two hit objects in reverse order.
|
||||||
|
/// </summary>
|
||||||
|
public class HitObjectReverseStartTimeComparer : Drawable.ReverseCreationOrderDepthComparer
|
||||||
|
{
|
||||||
|
public override int Compare(Drawable x, Drawable y)
|
||||||
|
{
|
||||||
|
var hitObjectX = x as DrawableHitObject;
|
||||||
|
var hitObjectY = y as DrawableHitObject;
|
||||||
|
|
||||||
|
// If either of the two drawables are not hit objects, fall back to the base comparer
|
||||||
|
if (hitObjectX?.HitObject == null || hitObjectY?.HitObject == null)
|
||||||
|
return base.Compare(x, y);
|
||||||
|
|
||||||
|
// Compare by start time
|
||||||
|
int i = hitObjectY.HitObject.StartTime.CompareTo(hitObjectX.HitObject.StartTime);
|
||||||
|
if (i != 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return base.Compare(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,20 +6,30 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy
|
namespace osu.Game.Rulesets.Objects.Legacy
|
||||||
{
|
{
|
||||||
internal abstract class ConvertSlider : HitObject, IHasCurve
|
internal abstract class ConvertSlider : HitObject, IHasCurve
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scoring distance with a speed-adjusted beat length of 1 second.
|
||||||
|
/// </summary>
|
||||||
|
private const float base_scoring_distance = 100;
|
||||||
|
|
||||||
public List<Vector2> ControlPoints { get; set; }
|
public List<Vector2> ControlPoints { get; set; }
|
||||||
public CurveType CurveType { get; set; }
|
public CurveType CurveType { get; set; }
|
||||||
|
|
||||||
public double Distance { get; set; }
|
public double Distance { get; set; }
|
||||||
|
|
||||||
public List<SampleInfoList> RepeatSamples { get; set; }
|
public List<SampleInfoList> RepeatSamples { get; set; }
|
||||||
public int RepeatCount { get; set; } = 1;
|
public int RepeatCount { get; set; } = 1;
|
||||||
|
|
||||||
public double EndTime { get; set; }
|
public double EndTime => StartTime + RepeatCount * Distance / Velocity;
|
||||||
public double Duration { get; set; }
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
|
public double Velocity = 1;
|
||||||
|
|
||||||
public Vector2 PositionAt(double progress)
|
public Vector2 PositionAt(double progress)
|
||||||
{
|
{
|
||||||
@ -35,5 +45,17 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
|
||||||
|
|
||||||
|
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / difficultyPoint.SpeedMultiplier;
|
||||||
|
|
||||||
|
Velocity = scoringDistance / timingPoint.BeatLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
{
|
{
|
||||||
case Key.Space:
|
case Key.Space:
|
||||||
osuLogo.TriggerClick(state);
|
osuLogo.TriggerOnClick(state);
|
||||||
return true;
|
return true;
|
||||||
case Key.Escape:
|
case Key.Escape:
|
||||||
switch (State)
|
switch (State)
|
||||||
@ -144,7 +144,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
State = MenuState.Initial;
|
State = MenuState.Initial;
|
||||||
return true;
|
return true;
|
||||||
case MenuState.Play:
|
case MenuState.Play:
|
||||||
backButton.TriggerClick();
|
backButton.TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +178,10 @@ namespace osu.Game.Screens.Menu
|
|||||||
State = MenuState.TopLevel;
|
State = MenuState.TopLevel;
|
||||||
return;
|
return;
|
||||||
case MenuState.TopLevel:
|
case MenuState.TopLevel:
|
||||||
buttonsTopLevel.First().TriggerClick();
|
buttonsTopLevel.First().TriggerOnClick();
|
||||||
return;
|
return;
|
||||||
case MenuState.Play:
|
case MenuState.Play:
|
||||||
buttonsPlay.First().TriggerClick();
|
buttonsPlay.First().TriggerOnClick();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,15 @@ namespace osu.Game.Screens
|
|||||||
Background.Exit();
|
Background.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnExiting(next);
|
if (base.OnExiting(next))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// while this is not necessary as we are constructing our own bindable, there are cases where
|
||||||
|
// the GC doesn't run as fast as expected and this is triggered post-exit.
|
||||||
|
// added to resolve https://github.com/ppy/osu/issues/829
|
||||||
|
beatmap.ValueChanged -= OnBeatmapChanged;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
if (!args.Repeat && args.Key == Key.Escape)
|
if (!args.Repeat && args.Key == Key.Escape)
|
||||||
{
|
{
|
||||||
Buttons.Children.Last().TriggerClick();
|
Buttons.Children.Last().TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public readonly ModDisplay ModDisplay;
|
public readonly ModDisplay ModDisplay;
|
||||||
|
|
||||||
private Bindable<bool> showHud;
|
private Bindable<bool> showHud;
|
||||||
|
private bool replayLoaded;
|
||||||
|
|
||||||
private static bool hasShownNotificationOnce;
|
private static bool hasShownNotificationOnce;
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ namespace osu.Game.Screens.Play
|
|||||||
protected abstract HealthDisplay CreateHealthDisplay();
|
protected abstract HealthDisplay CreateHealthDisplay();
|
||||||
protected abstract SongProgress CreateProgress();
|
protected abstract SongProgress CreateProgress();
|
||||||
protected abstract ModDisplay CreateModsContainer();
|
protected abstract ModDisplay CreateModsContainer();
|
||||||
|
//protected abstract ReplaySettingsOverlay CreateReplaySettingsOverlay();
|
||||||
|
|
||||||
protected HUDOverlay()
|
protected HUDOverlay()
|
||||||
{
|
{
|
||||||
@ -59,6 +61,7 @@ namespace osu.Game.Screens.Play
|
|||||||
HealthDisplay = CreateHealthDisplay(),
|
HealthDisplay = CreateHealthDisplay(),
|
||||||
Progress = CreateProgress(),
|
Progress = CreateProgress(),
|
||||||
ModDisplay = CreateModsContainer(),
|
ModDisplay = CreateModsContainer(),
|
||||||
|
//ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -93,11 +96,15 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
hitRenderer.InputManager.Add(KeyCounter.GetReceptor());
|
hitRenderer.InputManager.Add(KeyCounter.GetReceptor());
|
||||||
|
|
||||||
|
replayLoaded = hitRenderer.HasReplayLoaded;
|
||||||
|
|
||||||
// in the case a replay isn't loaded, we want some elements to only appear briefly.
|
// in the case a replay isn't loaded, we want some elements to only appear briefly.
|
||||||
if (!hitRenderer.HasReplayLoaded)
|
if (!replayLoaded)
|
||||||
|
{
|
||||||
using (ModDisplay.BeginDelayedSequence(2000))
|
using (ModDisplay.BeginDelayedSequence(2000))
|
||||||
ModDisplay.FadeOut(200);
|
ModDisplay.FadeOut(200);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
|
@ -131,13 +131,13 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
public override bool HandleInput => true;
|
public override bool HandleInput => true;
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => target.Children.Any(c => c.TriggerKeyDown(state, args));
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => target.Children.Any(c => c.TriggerOnKeyDown(state, args));
|
||||||
|
|
||||||
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => target.Children.Any(c => c.TriggerKeyUp(state, args));
|
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => target.Children.Any(c => c.TriggerOnKeyUp(state, args));
|
||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => target.Children.Any(c => c.TriggerMouseDown(state, args));
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => target.Children.Any(c => c.TriggerOnMouseDown(state, args));
|
||||||
|
|
||||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => target.Children.Any(c => c.TriggerMouseUp(state, args));
|
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => target.Children.Any(c => c.TriggerOnMouseUp(state, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
if (!args.Repeat && args.Key == Key.Escape)
|
if (!args.Repeat && args.Key == Key.Escape)
|
||||||
{
|
{
|
||||||
Buttons.Children.First().TriggerClick();
|
Buttons.Children.First().TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
protected override bool OnExiting(Screen next)
|
protected override bool OnExiting(Screen next)
|
||||||
{
|
{
|
||||||
if (HasFailed || !ValidForResume || pauseContainer.AllowExit || HitRenderer.HasReplayLoaded)
|
if (HasFailed || !ValidForResume || pauseContainer?.AllowExit != false || HitRenderer?.HasReplayLoaded != false)
|
||||||
{
|
{
|
||||||
fadeOut();
|
fadeOut();
|
||||||
return base.OnExiting(next);
|
return base.OnExiting(next);
|
||||||
@ -310,7 +310,7 @@ namespace osu.Game.Screens.Play
|
|||||||
HitRenderer?.FadeOut(fade_out_duration);
|
HitRenderer?.FadeOut(fade_out_duration);
|
||||||
Content.FadeOut(fade_out_duration);
|
Content.FadeOut(fade_out_duration);
|
||||||
|
|
||||||
hudOverlay.ScaleTo(0.7f, fade_out_duration * 3, EasingTypes.In);
|
hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, EasingTypes.In);
|
||||||
|
|
||||||
Background?.FadeTo(1f, fade_out_duration);
|
Background?.FadeTo(1f, fade_out_duration);
|
||||||
}
|
}
|
||||||
|
33
osu.Game/Screens/Play/ReplaySettings/CollectionSettings.cs
Normal file
33
osu.Game/Screens/Play/ReplaySettings/CollectionSettings.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays.Music;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.ReplaySettings
|
||||||
|
{
|
||||||
|
public class CollectionSettings : ReplayGroup
|
||||||
|
{
|
||||||
|
protected override string Title => @"collections";
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = @"Add current song to",
|
||||||
|
},
|
||||||
|
new CollectionsDropdown<PlaylistCollection>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Items = new[] { new KeyValuePair<string, PlaylistCollection>(@"All", PlaylistCollection.All) },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
osu.Game/Screens/Play/ReplaySettings/DiscussionSettings.cs
Normal file
35
osu.Game/Screens/Play/ReplaySettings/DiscussionSettings.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.ReplaySettings
|
||||||
|
{
|
||||||
|
public class DiscussionSettings : ReplayGroup
|
||||||
|
{
|
||||||
|
protected override string Title => @"discussions";
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new ReplayCheckbox
|
||||||
|
{
|
||||||
|
LabelText = "Show floating comments",
|
||||||
|
Bindable = config.GetBindable<bool>(OsuSetting.FloatingComments)
|
||||||
|
},
|
||||||
|
new FocusedTextBox
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 30,
|
||||||
|
PlaceholderText = "Add Comment",
|
||||||
|
HoldFocus = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs
Normal file
27
osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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.Game.Configuration;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.ReplaySettings
|
||||||
|
{
|
||||||
|
public class PlaybackSettings : ReplayGroup
|
||||||
|
{
|
||||||
|
protected override string Title => @"playback";
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new ReplaySliderBar<double>()
|
||||||
|
{
|
||||||
|
LabelText = "Playback speed",
|
||||||
|
Bindable = config.GetBindable<double>(OsuSetting.PlaybackSpeed)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
osu.Game/Screens/Play/ReplaySettings/ReplayCheckbox.cs
Normal file
20
osu.Game/Screens/Play/ReplaySettings/ReplayCheckbox.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.ReplaySettings
|
||||||
|
{
|
||||||
|
public class ReplayCheckbox : OsuCheckbox
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
Nub.AccentColour = colours.Yellow;
|
||||||
|
Nub.GlowingAccentColour = colours.YellowLighter;
|
||||||
|
Nub.GlowColour = colours.YellowDarker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
132
osu.Game/Screens/Play/ReplaySettings/ReplayGroup.cs
Normal file
132
osu.Game/Screens/Play/ReplaySettings/ReplayGroup.cs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.ReplaySettings
|
||||||
|
{
|
||||||
|
public abstract class ReplayGroup : Container
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The title to be displayed in the header of this group.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract string Title { get; }
|
||||||
|
|
||||||
|
private const float transition_duration = 250;
|
||||||
|
private const int container_width = 270;
|
||||||
|
private const int border_thickness = 2;
|
||||||
|
private const int header_height = 30;
|
||||||
|
private const int corner_radius = 5;
|
||||||
|
|
||||||
|
private readonly FillFlowContainer content;
|
||||||
|
private readonly IconButton button;
|
||||||
|
|
||||||
|
private bool expanded = true;
|
||||||
|
|
||||||
|
private Color4 buttonActiveColour;
|
||||||
|
|
||||||
|
protected ReplayGroup()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
Width = container_width;
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = corner_radius;
|
||||||
|
BorderColour = Color4.Black;
|
||||||
|
BorderThickness = border_thickness;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
Alpha = 0.5f,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = @"Header",
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = header_height,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Text = Title.ToUpper(),
|
||||||
|
TextSize = 17,
|
||||||
|
Font = @"Exo2.0-Bold",
|
||||||
|
Margin = new MarginPadding { Left = 10 },
|
||||||
|
},
|
||||||
|
button = new IconButton
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Position = new Vector2(-15,0),
|
||||||
|
Icon = FontAwesome.fa_bars,
|
||||||
|
Scale = new Vector2(0.75f),
|
||||||
|
Action = toggleContentVisibility,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
content = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = @"Content",
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeDuration = transition_duration,
|
||||||
|
AutoSizeEasing = EasingTypes.OutQuint,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding(15),
|
||||||
|
Spacing = new Vector2(0, 15),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
button.Colour = buttonActiveColour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
private void toggleContentVisibility()
|
||||||
|
{
|
||||||
|
content.ClearTransforms();
|
||||||
|
|
||||||
|
expanded = !expanded;
|
||||||
|
|
||||||
|
if (expanded)
|
||||||
|
content.AutoSizeAxes = Axes.Y;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content.AutoSizeAxes = Axes.None;
|
||||||
|
content.ResizeHeightTo(0, transition_duration, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.FadeColour(expanded ? buttonActiveColour : Color4.White, 200, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
osu.Game/Screens/Play/ReplaySettings/ReplaySliderBar.cs
Normal file
34
osu.Game/Screens/Play/ReplaySettings/ReplaySliderBar.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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.Game.Graphics.UserInterface;
|
||||||
|
using System;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Overlays.Settings;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.ReplaySettings
|
||||||
|
{
|
||||||
|
public class ReplaySliderBar<T> : SettingsSlider<T>
|
||||||
|
where T : struct, IEquatable<T>
|
||||||
|
{
|
||||||
|
protected override Drawable CreateControl() => new Sliderbar()
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding { Top = 5, Bottom = 5 },
|
||||||
|
RelativeSizeAxes = Axes.X
|
||||||
|
};
|
||||||
|
|
||||||
|
private class Sliderbar : OsuSliderBar<T>
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
AccentColour = colours.Yellow;
|
||||||
|
Nub.AccentColour = colours.Yellow;
|
||||||
|
Nub.GlowingAccentColour = colours.YellowLighter;
|
||||||
|
Nub.GlowColour = colours.YellowDarker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
osu.Game/Screens/Play/ReplaySettingsOverlay.cs
Normal file
24
osu.Game/Screens/Play/ReplaySettingsOverlay.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Screens.Play.ReplaySettings;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play
|
||||||
|
{
|
||||||
|
public class ReplaySettingsOverlay : FillFlowContainer
|
||||||
|
{
|
||||||
|
public ReplaySettingsOverlay()
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Vertical;
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Spacing = new Vector2(0, 20);
|
||||||
|
|
||||||
|
Add(new CollectionSettings());
|
||||||
|
Add(new DiscussionSettings());
|
||||||
|
Add(new PlaybackSettings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -127,7 +127,7 @@ namespace osu.Game.Screens.Play
|
|||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
{
|
{
|
||||||
case Key.Space:
|
case Key.Space:
|
||||||
button.TriggerClick();
|
button.TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user