Merge branch 'master' into editor-wheel-movement

This commit is contained in:
Dean Herbert 2018-03-16 15:56:51 +09:00 committed by GitHub
commit bca4b620b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
114 changed files with 866 additions and 588 deletions

@ -1 +1 @@
Subproject commit d29c8365ba3cf7924b57cf22341f4af55658764c
Subproject commit 41e2a0a4304544fb67779c21cad1435c105982d5

@ -1 +1 @@
Subproject commit 92ec3d10b12c5e9bfc1d3b05d3db174a506efd6d
Subproject commit 7bb0782200abadf73b79ed1a3bc1d5b926c6a81e

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
{
public override void PostProcess(Beatmap<CatchHitObject> beatmap)
{
if (beatmap.ComboColors.Count == 0)
if (beatmap.ComboColours.Count == 0)
return;
int index = 0;
@ -31,11 +31,11 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
if (obj.NewCombo)
{
if (lastObj != null) lastObj.LastInCombo = true;
colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count;
colourIndex = (colourIndex + 1) % beatmap.ComboColours.Count;
}
obj.IndexInBeatmap = index++;
obj.ComboColour = beatmap.ComboColors[colourIndex];
obj.ComboColour = beatmap.ComboColours[colourIndex];
lastObj = obj;
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.5;
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -7,5 +7,6 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModEasy : ModEasy
{
public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!";
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.5;
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -8,6 +8,5 @@ namespace osu.Game.Rulesets.Catch.Mods
public class CatchModHardRock : ModHardRock
{
public override double ScoreMultiplier => 1.12;
public override bool Ranked => true;
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModHidden : ModHidden
{
public override string Description => @"Play with fading notes for a slight score advantage.";
public override string Description => @"Play with fading fruits.";
public override double ScoreMultiplier => 1.06;
}
}

View File

@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
yield break;
}
var objects = IsForCurrentRuleset ? generateSpecific(original) : generateConverted(original);
var objects = IsForCurrentRuleset ? generateSpecific(original, beatmap) : generateConverted(original, beatmap);
if (objects == null)
yield break;
@ -110,10 +110,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// Method that generates hit objects for osu!mania specific beatmaps.
/// </summary>
/// <param name="original">The original hit object.</param>
/// <param name="originalBeatmap">The original beatmap. This is used to look-up any values dependent on a fully-loaded beatmap.</param>
/// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original)
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, Beatmap originalBeatmap)
{
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern);
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
Pattern newPattern = generator.Generate();
lastPattern = newPattern;
@ -125,26 +126,25 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// Method that generates hit objects for non-osu!mania beatmaps.
/// </summary>
/// <param name="original">The original hit object.</param>
/// <param name="originalBeatmap">The original beatmap. This is used to look-up any values dependent on a fully-loaded beatmap.</param>
/// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateConverted(HitObject original)
private IEnumerable<ManiaHitObject> generateConverted(HitObject original, Beatmap originalBeatmap)
{
var endTimeData = original as IHasEndTime;
var distanceData = original as IHasDistance;
var positionData = original as IHasPosition;
// Following lines currently commented out to appease resharper
Patterns.PatternGenerator conversion = null;
if (distanceData != null)
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern);
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
else if (endTimeData != null)
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap);
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, originalBeatmap);
else if (positionData != null)
{
computeDensity(original.StartTime);
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair);
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap);
recordNote(original.StartTime, positionData.Position);
}
@ -153,10 +153,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
return null;
Pattern newPattern = conversion.Generate();
lastPattern = newPattern;
var stairPatternGenerator = conversion as HitObjectPatternGenerator;
lastStair = stairPatternGenerator?.StairType ?? lastStair;
lastPattern = conversion is EndTimeObjectPatternGenerator ? lastPattern : newPattern;
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
return newPattern.HitObjects;
}
@ -166,8 +165,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary>
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
{
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern)
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, Beatmap originalBeatmap)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
{
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
@ -29,11 +30,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private PatternType convertType;
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern)
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, Beatmap originalBeatmap)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
{
convertType = PatternType.None;
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
if (!Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
convertType = PatternType.LowProbability;
var distanceData = hitObject as IHasDistance;
@ -305,19 +306,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
p4 = 0;
break;
case 3:
p2 = Math.Max(p2, 0.1);
p2 = Math.Min(p2, 0.1);
p3 = 0;
p4 = 0;
break;
case 4:
p2 = Math.Max(p2, 0.3);
p3 = Math.Max(p3, 0.04);
p2 = Math.Min(p2, 0.3);
p3 = Math.Min(p3, 0.04);
p4 = 0;
break;
case 5:
p2 = Math.Max(p2, 0.34);
p3 = Math.Max(p3, 0.1);
p4 = Math.Max(p4, 0.03);
p2 = Math.Min(p2, 0.34);
p3 = Math.Min(p3, 0.1);
p4 = Math.Min(p4, 0.03);
break;
}
@ -396,17 +397,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// Create the hold note
addToPattern(pattern, holdColumn, startTime, endTime);
int noteCount = 1;
int nextColumn = Random.Next(RandomStart, TotalColumns);
int noteCount;
if (ConversionDifficulty > 6.5)
noteCount = GetRandomNoteCount(0.63, 0);
else if (ConversionDifficulty > 4)
noteCount = GetRandomNoteCount(TotalColumns < 6 ? 0.12 : 0.45, 0);
else if (ConversionDifficulty > 2.5)
noteCount = GetRandomNoteCount(TotalColumns < 6 ? 0 : 0.24, 0);
else
noteCount = 0;
noteCount = Math.Min(TotalColumns - 1, noteCount);
bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP);
int nextColumn = Random.Next(RandomStart, TotalColumns);
var rowPattern = new Pattern();
for (int i = 0; i <= spanCount; i++)

View File

@ -7,6 +7,7 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using System.Linq;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
@ -15,8 +16,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
private readonly double endTime;
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap)
: base(random, hitObject, beatmap, new Pattern())
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Beatmap originalBeatmap)
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
{
var endtimeData = HitObject as IHasEndTime;

View File

@ -5,6 +5,7 @@ using System;
using System.Linq;
using OpenTK;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Mania.Objects;
@ -19,8 +20,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly PatternType convertType;
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair)
: base(random, hitObject, beatmap, previousPattern)
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair, Beatmap originalBeatmap)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
{
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
if (density < 0) throw new ArgumentOutOfRangeException(nameof(density));
@ -308,20 +309,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
p5 = 0;
break;
case 3:
p2 = Math.Max(p2, 0.1);
p2 = Math.Min(p2, 0.1);
p3 = 0;
p4 = 0;
p5 = 0;
break;
case 4:
p2 = Math.Max(p2, 0.23);
p3 = Math.Max(p3, 0.04);
p2 = Math.Min(p2, 0.23);
p3 = Math.Min(p3, 0.04);
p4 = 0;
p5 = 0;
break;
case 5:
p3 = Math.Max(p3, 0.15);
p4 = Math.Max(p4, 0.03);
p3 = Math.Min(p3, 0.15);
p4 = Math.Min(p4, 0.03);
p5 = 0;
break;
}
@ -355,23 +356,23 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
p3 = 0;
break;
case 3:
centreProbability = Math.Max(centreProbability, 0.03);
p2 = Math.Max(p2, 0.1);
centreProbability = Math.Min(centreProbability, 0.03);
p2 = 0;
p3 = 0;
break;
case 4:
centreProbability = 0;
p2 = Math.Max(p2 * 2, 0.2);
p2 = Math.Min(p2 * 2, 0.2);
p3 = 0;
break;
case 5:
centreProbability = Math.Max(centreProbability, 0.03);
centreProbability = Math.Min(centreProbability, 0.03);
p3 = 0;
break;
case 6:
centreProbability = 0;
p2 = Math.Max(p2 * 2, 0.5);
p3 = Math.Max(p3 * 2, 0.15);
p2 = Math.Min(p2 * 2, 0.5);
p3 = Math.Min(p3 * 2, 0.15);
break;
}

View File

@ -25,14 +25,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// </summary>
protected readonly FastRandom Random;
protected PatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
/// <summary>
/// The beatmap which <see cref="HitObject"/> is being converted from.
/// </summary>
protected readonly Beatmap OriginalBeatmap;
protected PatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, Beatmap originalBeatmap)
: base(hitObject, beatmap, previousPattern)
{
if (random == null) throw new ArgumentNullException(nameof(random));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
if (originalBeatmap == null) throw new ArgumentNullException(nameof(originalBeatmap));
Random = random;
OriginalBeatmap = originalBeatmap;
RandomStart = TotalColumns == 8 ? 1 : 0;
}
@ -94,17 +100,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (conversionDifficulty != null)
return conversionDifficulty.Value;
HitObject lastObject = Beatmap.HitObjects.LastOrDefault();
HitObject firstObject = Beatmap.HitObjects.FirstOrDefault();
HitObject lastObject = OriginalBeatmap.HitObjects.LastOrDefault();
HitObject firstObject = OriginalBeatmap.HitObjects.FirstOrDefault();
double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0);
drainTime -= Beatmap.TotalBreakTime;
drainTime -= OriginalBeatmap.TotalBreakTime;
if (drainTime == 0)
drainTime = 10000;
drainTime = 10000000;
BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.BaseDifficulty;
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15;
// We need this in seconds
drainTime /= 1000;
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15;
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
return conversionDifficulty.Value;

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.3;
public override double ScoreMultiplier => 0.5;
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1.0;
public override double ScoreMultiplier => 1;
}
}

View File

@ -16,8 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Dual Stages";
public override string ShortenedName => "DS";
public override string Description => @"Double the stages, double the fun!";
public override double ScoreMultiplier => 1;
public override bool Ranked => false;
public override double ScoreMultiplier => 0;
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
{

View File

@ -7,5 +7,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModEasy : ModEasy
{
public override string Description => @"More forgiving HP drain, less accuracy required, and three lives!";
}
}

View File

@ -9,10 +9,11 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModFadeIn : Mod
{
public override string Name => "FadeIn";
public override string Name => "Fade In";
public override string ShortenedName => "FI";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => @"Keys appear out of nowhere!";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) };

View File

@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModFlashlight : ModFlashlight
{
public override double ScoreMultiplier => 1.0;
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.3;
public override double ScoreMultiplier => 0.5;
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModHardRock : ModHardRock
{
public override double ScoreMultiplier => 1.0;
public override double ScoreMultiplier => 1;
}
}

View File

@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModHidden : ModHidden
{
public override string Description => @"The notes fade out before you hit them!";
public override double ScoreMultiplier => 1.0;
public override string Description => @"Keys fade out before you hit them!";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) };
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey1 : ManiaKeyMod
{
public override int KeyCount => 1;
public override string Name => "1K";
public override string Name => "One Key";
public override string ShortenedName => "1K";
public override string Description => @"Play with one key.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey2 : ManiaKeyMod
{
public override int KeyCount => 2;
public override string Name => "2K";
public override string Name => "Two Keys";
public override string ShortenedName => "2K";
public override string Description => @"Play with two keys.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey3 : ManiaKeyMod
{
public override int KeyCount => 3;
public override string Name => "3K";
public override string Name => "Three Keys";
public override string ShortenedName => "3K";
public override string Description => @"Play with three keys.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey4 : ManiaKeyMod
{
public override int KeyCount => 4;
public override string Name => "4K";
public override string Name => "Four Keys";
public override string ShortenedName => "4K";
public override string Description => @"Play with four keys.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey5 : ManiaKeyMod
{
public override int KeyCount => 5;
public override string Name => "5K";
public override string Name => "Five Keys";
public override string ShortenedName => "5K";
public override string Description => @"Play with five keys.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey6 : ManiaKeyMod
{
public override int KeyCount => 6;
public override string Name => "6K";
public override string Name => "Six Keys";
public override string ShortenedName => "6K";
public override string Description => @"Play with six keys.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey7 : ManiaKeyMod
{
public override int KeyCount => 7;
public override string Name => "7K";
public override string Name => "Seven Keys";
public override string ShortenedName => "7K";
public override string Description => @"Play with seven keys.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey8 : ManiaKeyMod
{
public override int KeyCount => 8;
public override string Name => "8K";
public override string Name => "Eight Keys";
public override string ShortenedName => "8K";
public override string Description => @"Play with eight keys.";
}
}

View File

@ -6,6 +6,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKey9 : ManiaKeyMod
{
public override int KeyCount => 9;
public override string Name => "9K";
public override string Name => "Nine Keys";
public override string ShortenedName => "9K";
public override string Description => @"Play with nine keys.";
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModNightcore : ModNightcore
{
public override double ScoreMultiplier => 1.0;
public override double ScoreMultiplier => 1;
}
}

View File

@ -17,8 +17,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Random";
public override string ShortenedName => "RD";
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
public override string Description => @"Shuffle around the notes!";
public override double ScoreMultiplier => 1;
public override string Description => @"Shuffle around the keys!";
public override double ScoreMultiplier => 0;
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{

View File

@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Tests
private bool isForCurrentRuleset;
[NonParallelizable]
[TestCase("basic", false), Ignore("See: https://github.com/ppy/osu/issues/2150")]
[TestCase("basic", false)]
public void Test(string name, bool isForCurrentRuleset)
{
this.isForCurrentRuleset = isForCurrentRuleset;

View File

@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{
applyStacking(beatmap);
if (beatmap.ComboColors.Count == 0)
if (beatmap.ComboColours.Count == 0)
return;
int comboIndex = 0;
@ -25,11 +25,11 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
if (obj.NewCombo)
{
comboIndex = 0;
colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count;
colourIndex = (colourIndex + 1) % beatmap.ComboColours.Count;
}
obj.IndexInCurrentCombo = comboIndex++;
obj.ComboColour = beatmap.ComboColors[colourIndex];
obj.ComboColour = beatmap.ComboColours[colourIndex];
}
}

View File

@ -1,26 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection
{
public class OsuHitObjectOverlayLayer : HitObjectOverlayLayer
{
protected override HitObjectOverlay CreateOverlayFor(DrawableHitObject hitObject)
{
switch (hitObject)
{
case DrawableHitCircle circle:
return new HitCircleOverlay(circle);
case DrawableSlider slider:
return new SliderOverlay(slider);
}
return base.CreateOverlayFor(hitObject);
}
}
}

View File

@ -4,15 +4,15 @@
using osu.Framework.Graphics;
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
{
public class HitCircleOverlay : HitObjectOverlay
public class HitCircleMask : HitObjectMask
{
public HitCircleOverlay(DrawableHitCircle hitCircle)
public HitCircleMask(DrawableHitCircle hitCircle)
: base(hitCircle)
{
Origin = Anchor.Centre;
@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
Scale = hitCircle.Scale;
AddInternal(new RingPiece());
hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.Position;
}
[BackgroundDependencyLoader]

View File

@ -4,7 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
@ -12,21 +12,21 @@ using OpenTK;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
{
public class SliderCircleOverlay : HitObjectOverlay
public class SliderCircleMask : HitObjectMask
{
public SliderCircleOverlay(DrawableHitCircle sliderHead, DrawableSlider slider)
public SliderCircleMask(DrawableHitCircle sliderHead, DrawableSlider slider)
: this(sliderHead, Vector2.Zero, slider)
{
}
public SliderCircleOverlay(DrawableSliderTail sliderTail, DrawableSlider slider)
public SliderCircleMask(DrawableSliderTail sliderTail, DrawableSlider slider)
: this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider)
{
}
private readonly DrawableOsuHitObject hitObject;
private SliderCircleOverlay(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider)
private SliderCircleMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider)
: base(hitObject)
{
this.hitObject = hitObject;

View File

@ -4,36 +4,41 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
{
public class SliderOverlay : HitObjectOverlay
public class SliderMask : HitObjectMask
{
private readonly SliderBody body;
private readonly DrawableSlider slider;
public SliderOverlay(DrawableSlider slider)
public SliderMask(DrawableSlider slider)
: base(slider)
{
this.slider = slider;
var obj = (Slider)slider.HitObject;
Position = slider.Position;
var sliderObject = (Slider)slider.HitObject;
InternalChildren = new Drawable[]
{
body = new SliderBody(obj)
body = new SliderBody(sliderObject)
{
AccentColour = Color4.Transparent,
PathWidth = obj.Scale * 64
PathWidth = sliderObject.Scale * 64
},
new SliderCircleOverlay(slider.HeadCircle, slider),
new SliderCircleOverlay(slider.TailCircle, slider),
new SliderCircleMask(slider.HeadCircle, slider),
new SliderCircleMask(slider.TailCircle, slider),
};
sliderObject.PositionChanged += _ => Position = slider.Position;
}
[BackgroundDependencyLoader]
@ -46,12 +51,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
{
base.Update();
Position = slider.Position;
Size = slider.Size;
OriginPosition = slider.OriginPosition;
// Need to cause one update
body.UpdateProgress(0);
}
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => body.ReceiveMouseInputAt(screenSpacePos);
}
}

View File

@ -5,10 +5,11 @@ using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI;
@ -32,6 +33,17 @@ namespace osu.Game.Rulesets.Osu.Edit
protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both };
protected override HitObjectOverlayLayer CreateHitObjectOverlayLayer() => new OsuHitObjectOverlayLayer();
public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject)
{
switch (hitObject)
{
case DrawableHitCircle circle:
return new HitCircleMask(circle);
case DrawableSlider slider:
return new SliderMask(slider);
}
return base.CreateMaskFor(hitObject);
}
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.5;
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -7,5 +7,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModEasy : ModEasy
{
public override string Description => @"Larger circles, more forgiving HP drain, less accuracy required, and three lives!";
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.5;
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModHardRock : ModHardRock, IApplicableToHitObject<OsuHitObject>
{
public override double ScoreMultiplier => 1.06;
public override bool Ranked => true;
public void ApplyToHitObject(OsuHitObject hitObject)
{

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModHidden : ModHidden, IApplicableToDrawableHitObjects
{
public override string Description => @"Play with no approach circles and fading notes for a slight score advantage.";
public override string Description => @"Play with no approach circles and fading circles/sliders.";
public override double ScoreMultiplier => 1.06;
private const double fade_in_duration_multiplier = 0.4;

View File

@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModRelax : ModRelax
{
public override string Description => "You don't need to click.\nGive your clicking/tapping finger a break from the heat of things.";
public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things.";
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
}

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Name => "Spun Out";
public override string ShortenedName => "SO";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
public override string Description => @"Spinners will be automatically completed";
public override string Description => @"Spinners will be automatically completed.";
public override double ScoreMultiplier => 0.9;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) };

View File

@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Name => "Target";
public override string ShortenedName => "TP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
public override string Description => @"";
public override string Description => @"Practice keeping up with the beat of the song.";
public override double ScoreMultiplier => 1;
}
}

View File

@ -66,6 +66,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
//may not be so correct
Size = circle.DrawSize;
HitObject.PositionChanged += _ => Position = HitObject.StackedPosition;
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)

View File

@ -83,6 +83,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
components.Add(drawableRepeatPoint);
AddNested(drawableRepeatPoint);
}
HitObject.PositionChanged += _ => Position = HitObject.StackedPosition;
}
[BackgroundDependencyLoader]

View File

@ -1,23 +1,41 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using OpenTK;
using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit.Types;
namespace osu.Game.Rulesets.Osu.Objects
{
public abstract class OsuHitObject : HitObject, IHasCombo, IHasPosition
public abstract class OsuHitObject : HitObject, IHasCombo, IHasEditablePosition
{
public const double OBJECT_RADIUS = 64;
public event Action<Vector2> PositionChanged;
public double TimePreempt = 600;
public double TimeFadein = 400;
public Vector2 Position { get; set; }
private Vector2 position;
public Vector2 Position
{
get => position;
set
{
if (position == value)
return;
position = value;
PositionChanged?.Invoke(value);
}
}
public float X => Position.X;
public float Y => Position.Y;
@ -48,5 +66,7 @@ namespace osu.Game.Rulesets.Osu.Objects
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
}
public virtual void OffsetPosition(Vector2 offset) => Position += offset;
}
}

View File

@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Objects
private void createSliderEnds()
{
HeadCircle = new HitCircle
HeadCircle = new SliderCircle(this)
{
StartTime = StartTime,
Position = Position,
@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.Objects
SampleControlPoint = SampleControlPoint
};
TailCircle = new HitCircle
TailCircle = new SliderCircle(this)
{
StartTime = EndTime,
Position = EndPosition,

View File

@ -0,0 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
namespace osu.Game.Rulesets.Osu.Objects
{
public class SliderCircle : HitCircle
{
private readonly Slider slider;
public SliderCircle(Slider slider)
{
this.slider = slider;
}
public override void OffsetPosition(Vector2 offset) => slider.OffsetPosition(offset);
}
}

View File

@ -0,0 +1,33 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics.Cursor;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
public class TestCaseGameplayCursor : OsuTestCase, IProvideCursor
{
private GameplayCursor cursor;
public override IReadOnlyList<Type> RequiredTypes => new [] { typeof(CursorTrail) };
public CursorContainer Cursor => cursor;
public bool ProvidingUserCursor => true;
[BackgroundDependencyLoader]
private void load()
{
Add(cursor = new GameplayCursor { RelativeSizeAxes = Axes.Both });
}
}
}

View File

@ -3,9 +3,9 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.OpenGL.Buffers;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Primitives;
@ -14,11 +14,12 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.Timing;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.ES30;
namespace osu.Game.Rulesets.Osu.UI.Cursor
{
internal class CursorTrail : Drawable
internal class CursorTrail : Drawable, IRequireHighFrequencyMousePosition
{
private int currentIndex;
@ -31,6 +32,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private float time;
public override bool IsPresent => true;
private readonly TrailDrawNodeSharedData trailDrawNodeSharedData = new TrailDrawNodeSharedData();
private const int max_sprites = 2048;
@ -96,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
const int fade_clock_reset_threshold = 1000000;
time = (float)(Time.Current - timeOffset) / 500f;
time = (float)(Time.Current - timeOffset) / 300f;
if (time > fade_clock_reset_threshold)
resetTime();
}
@ -115,14 +118,16 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
protected override bool OnMouseMove(InputState state)
{
Vector2 pos = state.Mouse.NativeState.Position;
if (lastPosition == null)
{
lastPosition = state.Mouse.NativeState.Position;
lastPosition = pos;
resampler.AddPosition(lastPosition.Value);
return base.OnMouseMove(state);
}
foreach (Vector2 pos2 in resampler.AddPosition(state.Mouse.NativeState.Position))
foreach (Vector2 pos2 in resampler.AddPosition(pos))
{
Trace.Assert(lastPosition.HasValue);
@ -162,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private class TrailDrawNodeSharedData
{
public VertexBuffer<TexturedVertex2D> VertexBuffer;
public VertexBuffer<TexturedTrailVertex> VertexBuffer;
}
private class TrailDrawNode : DrawNode
@ -188,7 +193,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
public override void Draw(Action<TexturedVertex2D> vertexAction)
{
if (Shared.VertexBuffer == null)
Shared.VertexBuffer = new QuadVertexBuffer<TexturedVertex2D>(max_sprites, BufferUsageHint.DynamicDraw);
Shared.VertexBuffer = new QuadVertexBuffer<TexturedTrailVertex>(max_sprites, BufferUsageHint.DynamicDraw);
Shader.GetUniform<float>("g_FadeClock").Value = Time;
@ -205,17 +210,19 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
int end = start;
Vector2 pos = Parts[i].Position;
ColourInfo colour = DrawInfo.Colour;
colour.TopLeft.Linear.A = Parts[i].Time + colour.TopLeft.Linear.A;
colour.TopRight.Linear.A = Parts[i].Time + colour.TopRight.Linear.A;
colour.BottomLeft.Linear.A = Parts[i].Time + colour.BottomLeft.Linear.A;
colour.BottomRight.Linear.A = Parts[i].Time + colour.BottomRight.Linear.A;
float time = Parts[i].Time;
Texture.DrawQuad(
new Quad(pos.X - Size.X / 2, pos.Y - Size.Y / 2, Size.X, Size.Y),
colour,
DrawInfo.Colour,
null,
v => Shared.VertexBuffer.Vertices[end++] = v);
v => Shared.VertexBuffer.Vertices[end++] = new TexturedTrailVertex
{
Position = v.Position,
TexturePosition = v.TexturePosition,
Time = time + 1,
Colour = v.Colour,
});
Parts[i].WasUpdated = false;
}
@ -240,5 +247,26 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
Shader.Unbind();
}
}
[StructLayout(LayoutKind.Sequential)]
public struct TexturedTrailVertex : IEquatable<TexturedTrailVertex>, IVertex
{
[VertexMember(2, VertexAttribPointerType.Float)]
public Vector2 Position;
[VertexMember(4, VertexAttribPointerType.Float)]
public Color4 Colour;
[VertexMember(2, VertexAttribPointerType.Float)]
public Vector2 TexturePosition;
[VertexMember(1, VertexAttribPointerType.Float)]
public float Time;
public bool Equals(TexturedTrailVertex other)
{
return Position.Equals(other.Position)
&& TexturePosition.Equals(other.TexturePosition)
&& Colour.Equals(other.Colour)
&& Time.Equals(other.Time);
}
}
}
}

View File

@ -20,13 +20,66 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
{
protected override Drawable CreateCursor() => new OsuCursor();
protected override Container<Drawable> Content => fadeContainer;
private readonly Container<Drawable> fadeContainer;
public GameplayCursor()
{
Add(new CursorTrail { Depth = 1 });
InternalChild = fadeContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new CursorTrail { Depth = 1 }
}
};
}
private int downCount;
public bool OnPressed(OsuAction action)
{
switch (action)
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
downCount++;
ActiveCursor.ScaleTo(1).ScaleTo(1.2f, 100, Easing.OutQuad);
break;
}
return false;
}
public bool OnReleased(OsuAction action)
{
switch (action)
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
if (--downCount == 0)
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
break;
}
return false;
}
public override bool HandleMouseInput => true; // OverlayContainer will set this false when we go hidden, but we always want to receive input.
protected override void PopIn()
{
fadeContainer.FadeTo(1, 300, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint);
ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint);
}
public class OsuCursor : Container
{
private Container cursorContainer;
@ -131,45 +184,5 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
cursorContainer.Scale = new Vector2(scale);
}
}
public bool OnPressed(OsuAction action)
{
switch (action)
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
downCount++;
ActiveCursor.ScaleTo(1).ScaleTo(1.2f, 100, Easing.OutQuad);
break;
}
return false;
}
public bool OnReleased(OsuAction action)
{
switch (action)
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
if (--downCount == 0)
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
break;
}
return false;
}
protected override void PopIn()
{
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
ActiveCursor.FadeTo(0, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(0.6f, 250, Easing.In);
}
}
}

View File

@ -64,10 +64,9 @@
<ItemGroup>
<Compile Include="Beatmaps\OsuBeatmapConverter.cs" />
<Compile Include="Beatmaps\OsuBeatmapProcessor.cs" />
<Compile Include="Edit\Layers\Selection\OsuHitObjectOverlayLayer.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\HitCircleOverlay.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\SliderCircleOverlay.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\SliderOverlay.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\HitCircleMask.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\SliderCircleMask.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\SliderMask.cs" />
<Compile Include="Edit\OsuEditPlayfield.cs" />
<Compile Include="Edit\OsuEditRulesetContainer.cs" />
<Compile Include="Edit\OsuHitObjectComposer.cs" />
@ -118,6 +117,7 @@
<Compile Include="Objects\Drawables\Pieces\SliderBody.cs" />
<Compile Include="Objects\ISliderProgress.cs" />
<Compile Include="Objects\RepeatPoint.cs" />
<Compile Include="Objects\SliderCircle.cs" />
<Compile Include="Objects\SliderTick.cs" />
<Compile Include="OsuDifficulty\OsuDifficultyCalculator.cs" />
<Compile Include="OsuDifficulty\Preprocessing\OsuDifficultyBeatmap.cs" />
@ -131,6 +131,7 @@
<Compile Include="Replays\OsuReplayInputHandler.cs" />
<Compile Include="Tests\OsuBeatmapConversionTest.cs" />
<Compile Include="Tests\TestCaseEditor.cs" />
<Compile Include="Tests\TestCaseGameplayCursor.cs" />
<Compile Include="Tests\TestCaseHitCircle.cs" />
<Compile Include="Tests\TestCaseHitCircleHidden.cs" />
<Compile Include="Tests\TestCasePerformancePoints.cs" />

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.5;
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -7,5 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModEasy : ModEasy
{
public override string Description => @"Beats move slower, less accuracy required, and three lives!";
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.5;
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -8,6 +8,5 @@ namespace osu.Game.Rulesets.Taiko.Mods
public class TaikoModHardRock : ModHardRock
{
public override double ScoreMultiplier => 1.06;
public override bool Ranked => true;
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModHidden : ModHidden
{
public override string Description => @"The notes fade out before you hit them!";
public override string Description => @"Beats fade out before you hit them!";
public override double ScoreMultiplier => 1.06;
}
}

View File

@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModRelax : ModRelax
{
public override string Description => @"Relax! You will no longer get dizzyfied by ninja-like spinners, demanding drumrolls or unexpected katu's.";
public override string Description => @"No ninja-like spinners, demanding drumrolls or unexpected katu's.";
}
}

View File

@ -167,7 +167,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var comboColors = decoder.Decode(stream).ComboColors;
var comboColors = decoder.Decode(stream).ComboColours;
Color4[] expectedColors =
{

View File

@ -102,9 +102,9 @@ namespace osu.Game.Tests.Beatmaps.Formats
new Color4(255, 187, 255, 255),
new Color4(255, 177, 140, 255),
};
Assert.AreEqual(expected.Length, beatmap.ComboColors.Count);
Assert.AreEqual(expected.Length, beatmap.ComboColours.Count);
for (int i = 0; i < expected.Length; i++)
Assert.AreEqual(expected[i], beatmap.ComboColors[i]);
Assert.AreEqual(expected[i], beatmap.ComboColours[i]);
}
[Test]

View File

@ -8,13 +8,12 @@ using osu.Framework.Allocation;
using OpenTK;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Edit;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Screens.Compose.Layers;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual
@ -24,17 +23,15 @@ namespace osu.Game.Tests.Visual
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(SelectionBox),
typeof(SelectionLayer),
typeof(CaptureBox),
typeof(SelectionBox),
typeof(HitObjectComposer),
typeof(OsuHitObjectComposer),
typeof(HitObjectOverlayLayer),
typeof(OsuHitObjectOverlayLayer),
typeof(HitObjectOverlay),
typeof(HitCircleOverlay),
typeof(SliderOverlay),
typeof(SliderCircleOverlay)
typeof(HitObjectMaskLayer),
typeof(HitObjectMask),
typeof(HitCircleMask),
typeof(SliderMask),
typeof(SliderCircleMask)
};
[BackgroundDependencyLoader]

View File

@ -13,7 +13,7 @@ namespace osu.Game.Tests.Visual
{
base.LoadComplete();
Add(new SkipButton(Clock.CurrentTime + 5000));
Add(new SkipOverlay(Clock.CurrentTime + 5000));
}
}
}

View File

@ -9,6 +9,7 @@ using System.Linq;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.IO.Serialization;
using Newtonsoft.Json;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO.Serialization.Converters;
namespace osu.Game.Beatmaps
@ -16,14 +17,14 @@ namespace osu.Game.Beatmaps
/// <summary>
/// A Beatmap containing converted HitObjects.
/// </summary>
public class Beatmap<T> : IJsonSerializable
public class Beatmap<T> : IJsonSerializable, IHasComboColours
where T : HitObject
{
public BeatmapInfo BeatmapInfo = new BeatmapInfo();
public ControlPointInfo ControlPointInfo = new ControlPointInfo();
public List<BreakPeriod> Breaks = new List<BreakPeriod>();
public List<Color4> ComboColors = new List<Color4>
public List<Color4> ComboColours { get; set; } = new List<Color4>
{
new Color4(17, 136, 170, 255),
new Color4(102, 136, 0, 255),
@ -55,7 +56,7 @@ namespace osu.Game.Beatmaps
BeatmapInfo = original?.BeatmapInfo.DeepClone() ?? BeatmapInfo;
ControlPointInfo = original?.ControlPointInfo ?? ControlPointInfo;
Breaks = original?.Breaks ?? Breaks;
ComboColors = original?.ComboColors ?? ComboColors;
ComboColours = original?.ComboColours ?? ComboColours;
HitObjects = original?.HitObjects ?? HitObjects;
if (original == null && Metadata == null)

View File

@ -50,9 +50,14 @@ namespace osu.Game.Beatmaps
protected virtual Beatmap<T> ConvertBeatmap(Beatmap original)
{
var beatmap = CreateBeatmap();
// todo: this *must* share logic (or directly use) Beatmap<T>'s constructor.
// right now this isn't easily possible due to generic entanglement.
beatmap.BeatmapInfo = original.BeatmapInfo;
beatmap.ControlPointInfo = original.ControlPointInfo;
beatmap.HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList();
beatmap.Breaks = original.Breaks;
beatmap.ComboColours = original.ComboColours;
return beatmap;
}

View File

@ -0,0 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Formats
{
public interface IHasComboColours
{
List<Color4> ComboColours { get; set; }
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Formats
{
public interface IHasCustomColours
{
Dictionary<string, Color4> CustomColours { get; set; }
}
}

View File

@ -5,7 +5,6 @@ using System;
using System.Globalization;
using System.IO;
using System.Linq;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Beatmaps.ControlPoints;
@ -19,7 +18,6 @@ namespace osu.Game.Beatmaps.Formats
private Beatmap beatmap;
private bool hasCustomColours;
private ConvertHitObjectParser parser;
private LegacySampleBank defaultSampleBank;
@ -72,29 +70,28 @@ namespace osu.Game.Beatmaps.Formats
{
case Section.General:
handleGeneral(line);
break;
return;
case Section.Editor:
handleEditor(line);
break;
return;
case Section.Metadata:
handleMetadata(line);
break;
return;
case Section.Difficulty:
handleDifficulty(line);
break;
return;
case Section.Events:
handleEvents(line);
break;
return;
case Section.TimingPoints:
handleTimingPoints(line);
break;
case Section.Colours:
handleColours(line);
break;
return;
case Section.HitObjects:
handleHitObjects(line);
break;
return;
}
base.ParseLine(beatmap, section, line);
}
private void handleGeneral(string line)
@ -364,38 +361,6 @@ namespace osu.Game.Beatmaps.Formats
}
}
private void handleColours(string line)
{
var pair = SplitKeyVal(line, ':');
string[] split = pair.Value.Split(',');
if (split.Length != 3)
throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}");
byte r, g, b;
if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b))
throw new InvalidOperationException(@"Color must be specified with 8-bit integer components");
if (!hasCustomColours)
{
beatmap.ComboColors.Clear();
hasCustomColours = true;
}
// Note: the combo index specified in the beatmap is discarded
if (pair.Key.StartsWith(@"Combo"))
{
beatmap.ComboColors.Add(new Color4
{
R = r / 255f,
G = g / 255f,
B = b / 255f,
A = 1f,
});
}
}
private void handleHitObjects(string line)
{
// If the ruleset wasn't specified, assume the osu!standard ruleset.

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Formats
{
@ -40,7 +41,53 @@ namespace osu.Game.Beatmaps.Formats
protected virtual bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.StartsWith("//");
protected abstract void ParseLine(T output, Section section, string line);
protected virtual void ParseLine(T output, Section section, string line)
{
switch (section)
{
case Section.Colours:
handleColours(output, line);
return;
}
}
private bool hasComboColours;
private void handleColours(T output, string line)
{
var pair = SplitKeyVal(line, ':');
bool isCombo = pair.Key.StartsWith(@"Combo");
string[] split = pair.Value.Split(',');
if (split.Length != 3)
throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}");
if (!byte.TryParse(split[0], out var r) || !byte.TryParse(split[1], out var g) || !byte.TryParse(split[2], out var b))
throw new InvalidOperationException(@"Color must be specified with 8-bit integer components");
Color4 colour = new Color4(r, g, b, 255);
if (isCombo)
{
if (!(output is IHasComboColours tHasComboColours)) return;
if (!hasComboColours)
{
// remove default colours.
tHasComboColours.ComboColours.Clear();
hasComboColours = true;
}
tHasComboColours.ComboColours.Add(colour);
}
else
{
if (!(output is IHasCustomColours tHasCustomColours)) return;
tHasCustomColours.CustomColours[pair.Key] = colour;
}
}
protected KeyValuePair<string, string> SplitKeyVal(string line, char separator)
{
@ -65,6 +112,7 @@ namespace osu.Game.Beatmaps.Formats
Colours,
HitObjects,
Variables,
Fonts
}
internal enum LegacySampleBank

View File

@ -46,11 +46,13 @@ namespace osu.Game.Beatmaps.Formats
{
case Section.Events:
handleEvents(line);
break;
return;
case Section.Variables:
handleVariables(line);
break;
return;
}
base.ParseLine(storyboard, section, line);
}
private void handleEvents(string line)

View File

@ -8,15 +8,17 @@ using System.Diagnostics;
using System.Net;
using System.Threading;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
namespace osu.Game.Online.API
{
public class APIAccess : IAPIProvider
public class APIAccess : Component, IAPIProvider
{
private readonly OsuConfigManager config;
private readonly OAuth authentication;
public string Endpoint = @"https://osu.ppy.sh";
@ -25,13 +27,12 @@ namespace osu.Game.Online.API
private ConcurrentQueue<APIRequest> queue = new ConcurrentQueue<APIRequest>();
public Scheduler Scheduler = new Scheduler();
/// <summary>
/// The username/email provided by the user when initiating a login.
/// </summary>
public string ProvidedUsername { get; private set; }
public string Username;
//private SecurePassword password;
public string Password;
private string password;
public Bindable<User> LocalUser { get; } = new Bindable<User>(createGuestUser());
@ -41,24 +42,31 @@ namespace osu.Game.Online.API
set { authentication.Token = string.IsNullOrEmpty(value) ? null : OAuthToken.Parse(value); }
}
protected bool HasLogin => Token != null || !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password);
protected bool HasLogin => Token != null || !string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password);
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable (should dispose of this or at very least keep a reference).
private readonly Thread thread;
private readonly Logger log;
public APIAccess()
public APIAccess(OsuConfigManager config)
{
this.config = config;
authentication = new OAuth(client_id, client_secret, Endpoint);
log = Logger.GetLogger(LoggingTarget.Network);
ProvidedUsername = config.Get<string>(OsuSetting.Username);
Token = config.Get<string>(OsuSetting.Token);
thread = new Thread(run) { IsBackground = true };
thread.Start();
}
private readonly List<IOnlineComponent> components = new List<IOnlineComponent>();
internal void Schedule(Action action) => base.Schedule(action);
public void Register(IOnlineComponent component)
{
Scheduler.Add(delegate
@ -111,12 +119,15 @@ namespace osu.Game.Online.API
State = APIState.Connecting;
if (!authentication.HasValidAccessToken && !authentication.AuthenticateWithLogin(Username, Password))
// save the username at this point, if the user requested for it to be.
config.Set(OsuSetting.Username, config.Get<bool>(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty);
if (!authentication.HasValidAccessToken && !authentication.AuthenticateWithLogin(ProvidedUsername, password))
{
//todo: this fails even on network-related issues. we should probably handle those differently.
//NotificationOverlay.ShowMessage("Login failed!");
log.Add(@"Login failed!");
Password = null;
password = null;
authentication.Clear();
continue;
}
@ -173,8 +184,8 @@ namespace osu.Game.Online.API
{
Debug.Assert(State == APIState.Offline);
Username = username;
Password = password;
ProvidedUsername = username;
this.password = password;
}
/// <summary>
@ -283,8 +294,8 @@ namespace osu.Game.Online.API
public void Logout(bool clearUsername = true)
{
flushQueue();
if (clearUsername) Username = null;
Password = null;
if (clearUsername) ProvidedUsername = null;
password = null;
authentication.Clear();
LocalUser.Value = createGuestUser();
}
@ -295,9 +306,12 @@ namespace osu.Game.Online.API
Id = 1,
};
public void Update()
protected override void Dispose(bool isDisposing)
{
Scheduler.Update();
base.Dispose(isDisposing);
config.Set(OsuSetting.Token, config.Get<bool>(OsuSetting.SavePassword) ? Token : string.Empty);
config.Save();
}
}

View File

@ -14,7 +14,7 @@ namespace osu.Game.Online.API
return request;
}
private void request_Progress(long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); });
private void request_Progress(long current, long total) => API.Schedule(() => Progress?.Invoke(current, total));
protected APIDownloadRequest()
{

View File

@ -85,7 +85,7 @@ namespace osu.Game.Online.API
if (checkAndProcessFailure())
return;
api.Scheduler.Add(delegate { Success?.Invoke(); });
api.Schedule(delegate { Success?.Invoke(); });
}
public void Cancel() => Fail(new OperationCanceledException(@"Request cancelled"));
@ -108,7 +108,7 @@ namespace osu.Game.Online.API
{
if (API == null || pendingFailure == null) return cancelled;
API.Scheduler.Add(pendingFailure);
API.Schedule(pendingFailure);
pendingFailure = null;
return true;
}

View File

@ -1,13 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework;
using osu.Framework.Configuration;
using osu.Game.Users;
namespace osu.Game.Online.API
{
public interface IAPIProvider : IUpdateable
public interface IAPIProvider
{
/// <summary>
/// The local user.

View File

@ -34,7 +34,7 @@ using osu.Game.Skinning;
namespace osu.Game
{
public class OsuGameBase : Framework.Game, IOnlineComponent, ICanAcceptFiles
public class OsuGameBase : Framework.Game, ICanAcceptFiles
{
protected OsuConfigManager LocalConfig;
@ -56,8 +56,6 @@ namespace osu.Game
protected override string MainResourceFile => @"osu.Game.Resources.dll";
public APIAccess API;
private Container content;
protected override Container<Drawable> Content => content;
@ -108,16 +106,14 @@ namespace osu.Game
dependencies.Cache(SkinManager = new SkinManager(Host.Storage, contextFactory, Host, Audio));
dependencies.Cache(API = new APIAccess
{
Username = LocalConfig.Get<string>(OsuSetting.Username),
Token = LocalConfig.Get<string>(OsuSetting.Token)
});
dependencies.CacheAs<IAPIProvider>(API);
var api = new APIAccess(LocalConfig);
dependencies.Cache(api);
dependencies.CacheAs<IAPIProvider>(api);
dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage));
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Host));
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, api, Host));
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory, Host, BeatmapManager, RulesetStore));
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore));
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory));
@ -183,9 +179,9 @@ namespace osu.Game
lastBeatmap = b;
};
API.Register(this);
FileStore.Cleanup();
AddInternal(api);
}
private void runMigrations()
@ -211,16 +207,6 @@ namespace osu.Game
private WorkingBeatmap lastBeatmap;
public void APIStateChanged(APIAccess api, APIState state)
{
switch (state)
{
case APIState.Online:
LocalConfig.Set(OsuSetting.Username, LocalConfig.Get<bool>(OsuSetting.SaveUsername) ? API.Username : string.Empty);
break;
}
}
protected override void LoadComplete()
{
base.LoadComplete();
@ -253,24 +239,6 @@ namespace osu.Game
base.SetHost(host);
}
protected override void Update()
{
base.Update();
API.Update();
}
protected override void Dispose(bool isDisposing)
{
//refresh token may have changed.
if (LocalConfig != null && API != null)
{
LocalConfig.Set(OsuSetting.Token, LocalConfig.Get<bool>(OsuSetting.SavePassword) ? API.Token : string.Empty);
LocalConfig.Save();
}
base.Dispose(isDisposing);
}
private readonly List<ICanAcceptFiles> fileImporters = new List<ICanAcceptFiles>();
public void Import(params string[] paths)

View File

@ -186,7 +186,7 @@ namespace osu.Game.Overlays.Direct
progressBar.FadeOut(500);
};
request.DownloadProgressed += progress => progressBar.Current.Value = progress;
request.DownloadProgressed += progress => Schedule(() => progressBar.Current.Value = progress);
request.Success += data =>
{

View File

@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Mods
public DifficultyIncreaseSection()
{
Header = @"Gameplay Difficulty Increase";
Header = @"Difficulty Increase";
}
}
}

View File

@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Mods
public DifficultyReductionSection()
{
Header = @"Gameplay Difficulty Reduction";
Header = @"Difficulty Reduction";
}
}
}

View File

@ -287,7 +287,7 @@ namespace osu.Game.Overlays.Mods
Anchor = Anchor.TopCentre,
Action = modButtonPressed,
},
new AssistedSection
new SpecialSection
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,

View File

@ -8,7 +8,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Overlays.Mods
{
public class AssistedSection : ModSection
public class SpecialSection : ModSection
{
protected override Key[] ToggleKeys => new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M };
public override ModType ModType => ModType.Special;
@ -19,9 +19,9 @@ namespace osu.Game.Overlays.Mods
SelectedColour = colours.BlueLight;
}
public AssistedSection()
public SpecialSection()
{
Header = @"Assisted";
Header = @"Special";
}
}
}

View File

@ -210,7 +210,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
{
PlaceholderText = "Email address",
RelativeSizeAxes = Axes.X,
Text = api?.Username ?? string.Empty,
Text = api?.ProvidedUsername ?? string.Empty,
TabbableContentContainer = this
},
password = new OsuPasswordTextBox

View File

@ -13,10 +13,10 @@ using osu.Framework.Logging;
using osu.Framework.MathUtils;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit.Layers;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Screens.Compose.Layers;
using osu.Game.Screens.Edit.Screens.Compose.RadioButtons;
namespace osu.Game.Rulesets.Edit
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Edit
return;
}
HitObjectOverlayLayer hitObjectOverlayLayer = CreateHitObjectOverlayLayer();
HitObjectMaskLayer hitObjectMaskLayer = new HitObjectMaskLayer(this);
SelectionLayer selectionLayer = new SelectionLayer(rulesetContainer.Playfield);
var layerBelowRuleset = new BorderLayer
@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Edit
layerAboveRuleset.Children = new Drawable[]
{
selectionLayer, // Below object overlays for input
hitObjectOverlayLayer,
hitObjectMaskLayer,
selectionLayer.CreateProxy() // Proxy above object overlays for selections
};
@ -121,8 +121,10 @@ namespace osu.Game.Rulesets.Edit
}
};
selectionLayer.ObjectSelected += hitObjectOverlayLayer.AddOverlay;
selectionLayer.ObjectDeselected += hitObjectOverlayLayer.RemoveOverlay;
selectionLayer.ObjectSelected += hitObjectMaskLayer.AddOverlay;
selectionLayer.ObjectDeselected += hitObjectMaskLayer.RemoveOverlay;
selectionLayer.SelectionCleared += hitObjectMaskLayer.RemoveSelectionOverlay;
selectionLayer.SelectionFinished += hitObjectMaskLayer.AddSelectionOverlay;
toolboxCollection.Items =
new[] { new RadioButton("Select", () => setCompositionTool(null)) }
@ -259,14 +261,22 @@ namespace osu.Game.Rulesets.Edit
protected abstract IReadOnlyList<ICompositionTool> CompositionTools { get; }
/// <summary>
/// Creates a <see cref="HitObjectMask"/> for a specific <see cref="DrawableHitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to create the overlay for.</param>
public virtual HitObjectMask CreateMaskFor(DrawableHitObject hitObject) => null;
/// <summary>
/// Creates a <see cref="SelectionBox"/> which outlines <see cref="DrawableHitObject"/>s
/// and handles all hitobject movement/pattern adjustments.
/// </summary>
/// <param name="overlays">The <see cref="DrawableHitObject"/> overlays.</param>
public virtual SelectionBox CreateSelectionOverlay(IReadOnlyList<HitObjectMask> overlays) => new SelectionBox(overlays);
/// <summary>
/// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>.
/// </summary>
protected virtual ScalableContainer CreateLayerContainer() => new ScalableContainer { RelativeSizeAxes = Axes.Both };
/// <summary>
/// Creates the <see cref="HitObjectOverlayLayer"/> which overlays selected <see cref="DrawableHitObject"/>s.
/// </summary>
protected virtual HitObjectOverlayLayer CreateHitObjectOverlayLayer() => new HitObjectOverlayLayer();
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Edit
{
/// <summary>
/// A mask placed above a <see cref="DrawableHitObject"/> adding editing functionality.
/// </summary>
public class HitObjectMask : Container
{
public readonly DrawableHitObject HitObject;
public HitObjectMask(DrawableHitObject hitObject)
{
HitObject = hitObject;
}
}
}

View File

@ -1,68 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Edit.Layers.Selection
{
/// <summary>
/// A box which encloses <see cref="DrawableHitObject"/>s.
/// </summary>
public class CaptureBox : VisibilityContainer
{
private readonly IDrawable captureArea;
private readonly IReadOnlyList<DrawableHitObject> capturedObjects;
public CaptureBox(IDrawable captureArea, IReadOnlyList<DrawableHitObject> capturedObjects)
{
this.captureArea = captureArea;
this.capturedObjects = capturedObjects;
Masking = true;
BorderThickness = SelectionBox.BORDER_RADIUS;
InternalChild = new Box
{
RelativeSizeAxes = Axes.Both,
AlwaysPresent = true,
Alpha = 0
};
State = Visibility.Visible;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BorderColour = colours.Yellow;
// Move the rectangle to cover the hitobjects
var topLeft = new Vector2(float.MaxValue, float.MaxValue);
var bottomRight = new Vector2(float.MinValue, float.MinValue);
foreach (var obj in capturedObjects)
{
topLeft = Vector2.ComponentMin(topLeft, captureArea.ToLocalSpace(obj.SelectionQuad.TopLeft));
bottomRight = Vector2.ComponentMax(bottomRight, captureArea.ToLocalSpace(obj.SelectionQuad.BottomRight));
}
topLeft -= new Vector2(5);
bottomRight += new Vector2(5);
Size = bottomRight - topLeft;
Position = topLeft;
}
public override bool DisposeOnDeathRemoval => true;
protected override void PopIn() => this.FadeIn();
protected override void PopOut() => this.FadeOut();
}
}

View File

@ -1,25 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Edit.Layers.Selection
{
public class HitObjectOverlay : OverlayContainer
{
// ReSharper disable once NotAccessedField.Local
// This will be used later to handle drag movement, etc
private readonly DrawableHitObject hitObject;
public HitObjectOverlay(DrawableHitObject hitObject)
{
this.hitObject = hitObject;
State = Visibility.Visible;
}
protected override void PopIn() => Alpha = 1;
protected override void PopOut() => Alpha = 0;
}
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2007-2018 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.Graphics.Primitives;
using osu.Framework.Graphics.Shapes;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Edit.Layers.Selection
{
/// <summary>
/// A box that represents a drag selection.
/// </summary>
public class SelectionBox : VisibilityContainer
{
public const float BORDER_RADIUS = 2;
/// <summary>
/// Creates a new <see cref="SelectionBox"/>.
/// </summary>
public SelectionBox()
{
Masking = true;
BorderColour = Color4.White;
BorderThickness = BORDER_RADIUS;
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.1f
};
}
public void SetDragRectangle(RectangleF rectangle)
{
var topLeft = Parent.ToLocalSpace(rectangle.TopLeft);
var bottomRight = Parent.ToLocalSpace(rectangle.BottomRight);
Position = topLeft;
Size = bottomRight - topLeft;
}
public override bool DisposeOnDeathRemoval => true;
protected override void PopIn() => this.FadeIn(250, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(250, Easing.OutQuint);
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Types;
using OpenTK;
namespace osu.Game.Rulesets.Edit.Types
{
public interface IHasEditablePosition : IHasPosition
{
void OffsetPosition(Vector2 offset);
}
}

View File

@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "Autoplay";
public override string ShortenedName => "AT";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto;
public override string Description => "Watch a perfect automated play through the song";
public override string Description => "Watch a perfect automated play through the song.";
public override double ScoreMultiplier => 0;
public bool AllowFail => false;
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) };

View File

@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Mods
public override string ShortenedName => "CN";
public override bool HasImplementation => false;
public override FontAwesome Icon => FontAwesome.fa_osu_mod_cinema;
public override string Description => "Watch the video without visual distractions.";
}
}

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "Daycore";
public override string ShortenedName => "DC";
public override FontAwesome Icon => FontAwesome.fa_question;
public override string Description => "whoaaaaa";
public override string Description => "Whoaaaaa...";
public override void ApplyToClock(IAdjustableClock clock)
{

View File

@ -7,18 +7,16 @@ using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
public class ModDoubleTime : Mod, IApplicableToClock
public abstract class ModDoubleTime : Mod, IApplicableToClock
{
public override string Name => "Double Time";
public override string ShortenedName => "DT";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_doubletime;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => "Zoooooooooom";
public override string Description => "Zoooooooooom...";
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModHalfTime) };
public override double ScoreMultiplier => 1.12;
public virtual void ApplyToClock(IAdjustableClock clock)
{
clock.Rate = 1.5;

View File

@ -13,7 +13,6 @@ namespace osu.Game.Rulesets.Mods
public override string ShortenedName => "EZ";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_easy;
public override ModType Type => ModType.DifficultyReduction;
public override string Description => "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required.";
public override double ScoreMultiplier => 0.5;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) };

View File

@ -13,12 +13,10 @@ namespace osu.Game.Rulesets.Mods
public override string ShortenedName => "HT";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_halftime;
public override ModType Type => ModType.DifficultyReduction;
public override string Description => "Less zoom";
public override string Description => "Less zoom...";
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModDoubleTime) };
public override double ScoreMultiplier => 1.12;
public virtual void ApplyToClock(IAdjustableClock clock)
{
clock.Rate = 0.75;

View File

@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Mods
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hardrock;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => "Everything just got a bit harder...";
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModEasy) };
public void ApplyToDifficulty(BeatmapDifficulty difficulty)

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "Nightcore";
public override string ShortenedName => "NC";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nightcore;
public override string Description => "uguuuuuuuu";
public override string Description => "Uguuuuuuuu...";
public override void ApplyToClock(IAdjustableClock clock)
{

View File

@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mods
{
public abstract class ModNoFail : Mod, IApplicableFailOverride
{
public override string Name => "NoFail";
public override string Name => "No Fail";
public override string ShortenedName => "NF";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nofail;
public override ModType Type => ModType.DifficultyReduction;

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