mirror of
https://github.com/ppy/osu.git
synced 2026-05-13 22:43:24 +08:00
Compare commits
1273 Commits
test2
...
v2018.319.0
+7
-5
@@ -1,9 +1,11 @@
|
||||
osu!lazer is currently in early stages of development and is not yet ready for end users. Please avoid creating issues or bugs if you do not personally intend to fix them. Some acceptable topics include:
|
||||
osu!lazer is currently still under heavy development!
|
||||
|
||||
Please ensure that you are making an issue for one of the following:
|
||||
|
||||
- A bug with currently implemented features (not features that don't exist)
|
||||
- A feature you are considering adding, so we can collaborate on feedback and design.
|
||||
- Discussions about technical design decisions
|
||||
- Bugs that you have found and are personally willing and able to fix
|
||||
- TODO lists of smaller tasks around larger features
|
||||
|
||||
Basically, issues are not a place for you to get help. They are a place for developers to collaborate on the game.
|
||||
|
||||
If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide.
|
||||
|
||||
Screenshots and log files are highly welcomed.
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+5
-1
@@ -12,7 +12,7 @@ install:
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- cmd: choco install resharper-clt -y
|
||||
- cmd: choco install nvika -y
|
||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.3/CodeFileSanity.exe
|
||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe
|
||||
before_build:
|
||||
- cmd: CodeFileSanity.exe
|
||||
- cmd: nuget restore -verbosity quiet
|
||||
@@ -20,6 +20,10 @@ build:
|
||||
project: osu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
test:
|
||||
assemblies:
|
||||
only:
|
||||
- 'osu.Desktop\**\*.dll'
|
||||
after_build:
|
||||
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
|
||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
+1
-1
Submodule osu-framework updated: 8f36ddab94...41e2a0a430
+1
-1
Submodule osu-resources updated: 7724abdf1d...7bb0782200
@@ -111,16 +111,11 @@ namespace osu.Desktop
|
||||
{
|
||||
var filePaths = new [] { e.FileName };
|
||||
|
||||
if (filePaths.All(f => Path.GetExtension(f) == @".osz"))
|
||||
Task.Factory.StartNew(() => BeatmapManager.Import(filePaths), TaskCreationOptions.LongRunning);
|
||||
else if (filePaths.All(f => Path.GetExtension(f) == @".osr"))
|
||||
Task.Run(() =>
|
||||
{
|
||||
var score = ScoreStore.ReadReplayFile(filePaths.First());
|
||||
Schedule(() => LoadScore(score));
|
||||
});
|
||||
}
|
||||
var firstExtension = Path.GetExtension(filePaths.First());
|
||||
|
||||
private static readonly string[] allowed_extensions = { @".osz", @".osr" };
|
||||
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
|
||||
|
||||
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.IPC;
|
||||
@@ -15,6 +16,9 @@ namespace osu.Desktop
|
||||
[STAThread]
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
if (!RuntimeInfo.IsMono)
|
||||
useMulticoreJit();
|
||||
|
||||
// Back up the cwd before DesktopGameHost changes it
|
||||
var cwd = Environment.CurrentDirectory;
|
||||
|
||||
@@ -22,7 +26,7 @@ namespace osu.Desktop
|
||||
{
|
||||
if (!host.IsPrimaryInstance)
|
||||
{
|
||||
var importer = new BeatmapIPCChannel(host);
|
||||
var importer = new ArchiveImportIPCChannel(host);
|
||||
// Restore the cwd so relative paths given at the command line work correctly
|
||||
Directory.SetCurrentDirectory(cwd);
|
||||
foreach (var file in args)
|
||||
@@ -44,8 +48,16 @@ namespace osu.Desktop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void useMulticoreJit()
|
||||
{
|
||||
var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
|
||||
ProfileOptimization.SetProfileRoot(directory.FullName);
|
||||
ProfileOptimization.StartProfile("Startup.Profile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.11\lib\net45\OpenTK.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
<description>click the circles. to the beat.</description>
|
||||
<summary>click the circles.</summary>
|
||||
<releaseNotes>testing</releaseNotes>
|
||||
<copyright>Copyright ppy Pty Ltd 2007-2017</copyright>
|
||||
<copyright>Copyright ppy Pty Ltd 2007-2018</copyright>
|
||||
<language>en-AU</language>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="*.exe" target="lib\net45\" exclude="**vshost**"/>
|
||||
<file src="*.dll" target="lib\net45\"/>
|
||||
<file src="*.dll" target="lib\net45\"/>
|
||||
<file src="*.config" target="lib\net45\"/>
|
||||
<file src="x86\*.dll" target="lib\net45\x86\"/>
|
||||
<file src="x64\*.dll" target="lib\net45\x64\"/>
|
||||
|
||||
@@ -6,7 +6,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
<packages>
|
||||
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" />
|
||||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
|
||||
<package id="SharpCompress" version="0.18.1" targetFramework="net461" />
|
||||
<package id="Splat" version="2.0.0" targetFramework="net45" />
|
||||
<package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,5 @@ namespace osu.Game.Rulesets.Catch
|
||||
MoveRight,
|
||||
[Description("Engage dash")]
|
||||
Dash,
|
||||
PositionUpdate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ using osu.Game.Rulesets.UI;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Replays.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch
|
||||
{
|
||||
@@ -99,7 +101,9 @@ namespace osu.Game.Rulesets.Catch
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);
|
||||
|
||||
public override int LegacyID => 2;
|
||||
public override int? LegacyID => 2;
|
||||
|
||||
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
|
||||
|
||||
public CatchRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
Origin = Anchor.BottomLeft;
|
||||
X = 0;
|
||||
|
||||
Child = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
|
||||
InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
foreach (var b in s.NestedHitObjects.Cast<BananaShower.Banana>())
|
||||
AddNested(getVisualRepresentation?.Invoke(b));
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
if (CheckPosition == null) return;
|
||||
|
||||
if (timeOffset > 0)
|
||||
if (timeOffset >= 0)
|
||||
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Child = new Pulp
|
||||
InternalChild = new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = Size
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new[]
|
||||
InternalChildren = new[]
|
||||
{
|
||||
createPulp(HitObject.VisualRepresentation),
|
||||
border = new Circle
|
||||
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
|
||||
if (HitObject.HyperDash)
|
||||
{
|
||||
Add(new Pulp
|
||||
AddInternal(new Pulp
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
|
||||
@@ -20,12 +20,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
Origin = Anchor.BottomLeft;
|
||||
X = 0;
|
||||
|
||||
Child = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, };
|
||||
InternalChild = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, };
|
||||
|
||||
foreach (var o in s.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddNested(getVisualRepresentation?.Invoke(o));
|
||||
}
|
||||
|
||||
protected override bool ProvidesJudgement => false;
|
||||
|
||||
protected override void AddNested(DrawableHitObject h)
|
||||
{
|
||||
var catchObject = (DrawableCatchHitObject)h;
|
||||
|
||||
@@ -21,9 +21,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
/// </summary>
|
||||
private const float base_scoring_distance = 100;
|
||||
|
||||
public readonly SliderCurve Curve = new SliderCurve();
|
||||
|
||||
public int RepeatCount { get; set; } = 1;
|
||||
public int RepeatCount { get; set; }
|
||||
|
||||
public double Velocity;
|
||||
public double TickDistance;
|
||||
@@ -55,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
var length = Curve.Distance;
|
||||
var tickDistance = Math.Min(TickDistance, length);
|
||||
var repeatDuration = length / Velocity;
|
||||
var spanDuration = length / Velocity;
|
||||
|
||||
var minDistanceFromEnd = Velocity * 0.01;
|
||||
|
||||
@@ -67,10 +65,10 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
X = X
|
||||
});
|
||||
|
||||
for (var repeat = 0; repeat < RepeatCount; repeat++)
|
||||
for (var span = 0; span < this.SpanCount(); span++)
|
||||
{
|
||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
||||
var reversed = repeat % 2 == 1;
|
||||
var spanStartTime = StartTime + span * spanDuration;
|
||||
var reversed = span % 2 == 1;
|
||||
|
||||
for (var d = tickDistance; d <= length; d += tickDistance)
|
||||
{
|
||||
@@ -80,12 +78,12 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
var timeProgress = d / length;
|
||||
var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
|
||||
|
||||
var lastTickTime = repeatStartTime + timeProgress * repeatDuration;
|
||||
var lastTickTime = spanStartTime + timeProgress * spanDuration;
|
||||
AddNested(new Droplet
|
||||
{
|
||||
StartTime = lastTickTime,
|
||||
ComboColour = ComboColour,
|
||||
X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
|
||||
X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
|
||||
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
|
||||
{
|
||||
Bank = s.Bank,
|
||||
@@ -95,19 +93,19 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
});
|
||||
}
|
||||
|
||||
double tinyTickInterval = tickDistance / length * repeatDuration;
|
||||
double tinyTickInterval = tickDistance / length * spanDuration;
|
||||
while (tinyTickInterval > 100)
|
||||
tinyTickInterval /= 2;
|
||||
|
||||
for (double t = 0; t < repeatDuration; t += tinyTickInterval)
|
||||
for (double t = 0; t < spanDuration; t += tinyTickInterval)
|
||||
{
|
||||
double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration;
|
||||
double progress = reversed ? 1 - t / spanDuration : t / spanDuration;
|
||||
|
||||
AddNested(new TinyDroplet
|
||||
{
|
||||
StartTime = repeatStartTime + t,
|
||||
StartTime = spanStartTime + t,
|
||||
ComboColour = ComboColour,
|
||||
X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
|
||||
X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
|
||||
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
|
||||
{
|
||||
Bank = s.Bank,
|
||||
@@ -121,15 +119,15 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
Samples = Samples,
|
||||
ComboColour = ComboColour,
|
||||
StartTime = repeatStartTime + repeatDuration,
|
||||
X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
|
||||
StartTime = spanStartTime + spanDuration,
|
||||
X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity;
|
||||
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
|
||||
|
||||
public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH;
|
||||
public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH;
|
||||
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
@@ -139,6 +137,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
set { Curve.Distance = value; }
|
||||
}
|
||||
|
||||
public SliderCurve Curve { get; } = new SliderCurve();
|
||||
|
||||
public List<Vector2> ControlPoints
|
||||
{
|
||||
get { return Curve.ControlPoints; }
|
||||
@@ -152,17 +152,5 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
get { return Curve.CurveType; }
|
||||
set { Curve.CurveType = value; }
|
||||
}
|
||||
|
||||
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
|
||||
|
||||
public double ProgressAt(double progress)
|
||||
{
|
||||
double p = progress * RepeatCount % 1;
|
||||
if (RepeatAt(progress) % 2 == 1)
|
||||
p = 1 - p;
|
||||
return p;
|
||||
}
|
||||
|
||||
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +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 System;
|
||||
using System.Linq;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Users;
|
||||
|
||||
@@ -23,15 +26,78 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
|
||||
public override Replay Generate()
|
||||
{
|
||||
// todo: add support for HT DT
|
||||
const double dash_speed = CatcherArea.Catcher.BASE_SPEED;
|
||||
const double movement_speed = dash_speed / 2;
|
||||
float lastPosition = 0.5f;
|
||||
double lastTime = 0;
|
||||
|
||||
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
|
||||
Replay.Frames.Add(new CatchReplayFrame(-100000, 0));
|
||||
Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition));
|
||||
|
||||
void moveToNext(CatchHitObject h)
|
||||
{
|
||||
float positionChange = Math.Abs(lastPosition - h.X);
|
||||
double timeAvailable = h.StartTime - lastTime;
|
||||
|
||||
//So we can either make it there without a dash or not.
|
||||
double speedRequired = positionChange / timeAvailable;
|
||||
|
||||
bool dashRequired = speedRequired > movement_speed && h.StartTime != 0;
|
||||
|
||||
// todo: get correct catcher size, based on difficulty CS.
|
||||
const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f;
|
||||
|
||||
if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X)
|
||||
{
|
||||
//we are already in the correct range.
|
||||
lastTime = h.StartTime;
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition));
|
||||
return;
|
||||
}
|
||||
|
||||
if (h is BananaShower.Banana)
|
||||
{
|
||||
// auto bananas unrealistically warp to catch 100% combo.
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
else if (h.HyperDash)
|
||||
{
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
else if (dashRequired)
|
||||
{
|
||||
//we do a movement in two parts - the dash part then the normal part...
|
||||
double timeAtNormalSpeed = positionChange / movement_speed;
|
||||
double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable;
|
||||
double timeAtDashSpeed = timeWeNeedToSave / 2;
|
||||
|
||||
float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
|
||||
|
||||
//dash movement
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, true));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
else
|
||||
{
|
||||
double timeBefore = positionChange / movement_speed;
|
||||
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
|
||||
lastTime = h.StartTime;
|
||||
lastPosition = h.X;
|
||||
}
|
||||
|
||||
foreach (var obj in Beatmap.HitObjects)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case Fruit _:
|
||||
Replay.Frames.Add(new CatchReplayFrame(obj.StartTime, obj.X));
|
||||
moveToNext(obj);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -42,7 +108,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
case BananaShower.Banana _:
|
||||
case TinyDroplet _:
|
||||
case Droplet _:
|
||||
Replay.Frames.Add(new CatchReplayFrame(nestedObj.StartTime, nestedObj.X));
|
||||
moveToNext(nestedObj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,26 +3,54 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Replays
|
||||
{
|
||||
public class CatchFramedReplayInputHandler : FramedReplayInputHandler
|
||||
public class CatchFramedReplayInputHandler : FramedReplayInputHandler<CatchReplayFrame>
|
||||
{
|
||||
public CatchFramedReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
public override List<InputState> GetPendingStates() => new List<InputState>
|
||||
protected override bool IsImportant(CatchReplayFrame frame) => frame.Position > 0;
|
||||
|
||||
protected float? Position
|
||||
{
|
||||
new CatchReplayState
|
||||
get
|
||||
{
|
||||
PressedActions = new List<CatchAction> { CatchAction.PositionUpdate },
|
||||
CatcherX = ((CatchReplayFrame)CurrentFrame).MouseX
|
||||
},
|
||||
new CatchReplayState { PressedActions = new List<CatchAction>() },
|
||||
};
|
||||
if (!HasFrames)
|
||||
return null;
|
||||
|
||||
return Interpolation.ValueAt(CurrentTime, CurrentFrame.Position, NextFrame.Position, CurrentFrame.Time, NextFrame.Time);
|
||||
}
|
||||
}
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
if (!Position.HasValue) return new List<InputState>();
|
||||
|
||||
var actions = new List<CatchAction>();
|
||||
|
||||
if (CurrentFrame.Dashing)
|
||||
actions.Add(CatchAction.Dash);
|
||||
|
||||
if (Position.Value > CurrentFrame.Position)
|
||||
actions.Add(CatchAction.MoveRight);
|
||||
else if (Position.Value < CurrentFrame.Position)
|
||||
actions.Add(CatchAction.MoveLeft);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new CatchReplayState
|
||||
{
|
||||
PressedActions = actions,
|
||||
CatcherX = Position.Value
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public class CatchReplayState : ReplayState<CatchAction>
|
||||
{
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Replays.Legacy;
|
||||
using osu.Game.Rulesets.Replays.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Replays
|
||||
{
|
||||
public class CatchReplayFrame : ReplayFrame
|
||||
public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame
|
||||
{
|
||||
public override bool IsImportant => MouseX > 0;
|
||||
public float Position;
|
||||
public bool Dashing;
|
||||
|
||||
public CatchReplayFrame(double time, float? x = null)
|
||||
: base(time, x ?? -1, null, ReplayButtonState.None)
|
||||
public CatchReplayFrame()
|
||||
{
|
||||
}
|
||||
|
||||
public CatchReplayFrame(double time, float? position = null, bool dashing = false)
|
||||
: base(time)
|
||||
{
|
||||
Position = position ?? -1;
|
||||
Dashing = dashing;
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
|
||||
{
|
||||
Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
||||
Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,957 @@
|
||||
{
|
||||
"Mappings": [{
|
||||
"StartTime": 500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 500.0,
|
||||
"Position": 96.0
|
||||
}, {
|
||||
"StartTime": 562.0,
|
||||
"Position": 100.84
|
||||
}, {
|
||||
"StartTime": 625.0,
|
||||
"Position": 125.0
|
||||
}, {
|
||||
"StartTime": 687.0,
|
||||
"Position": 152.84
|
||||
}, {
|
||||
"StartTime": 750.0,
|
||||
"Position": 191.0
|
||||
}, {
|
||||
"StartTime": 812.0,
|
||||
"Position": 212.84
|
||||
}, {
|
||||
"StartTime": 875.0,
|
||||
"Position": 217.0
|
||||
}, {
|
||||
"StartTime": 937.0,
|
||||
"Position": 234.84
|
||||
}, {
|
||||
"StartTime": 1000.0,
|
||||
"Position": 256.0
|
||||
}, {
|
||||
"StartTime": 1062.0,
|
||||
"Position": 267.84
|
||||
}, {
|
||||
"StartTime": 1125.0,
|
||||
"Position": 284.0
|
||||
}, {
|
||||
"StartTime": 1187.0,
|
||||
"Position": 311.84
|
||||
}, {
|
||||
"StartTime": 1250.0,
|
||||
"Position": 350.0
|
||||
}, {
|
||||
"StartTime": 1312.0,
|
||||
"Position": 359.84
|
||||
}, {
|
||||
"StartTime": 1375.0,
|
||||
"Position": 367.0
|
||||
}, {
|
||||
"StartTime": 1437.0,
|
||||
"Position": 400.84
|
||||
}, {
|
||||
"StartTime": 1500.0,
|
||||
"Position": 416.0
|
||||
}, {
|
||||
"StartTime": 1562.0,
|
||||
"Position": 377.159973
|
||||
}, {
|
||||
"StartTime": 1625.0,
|
||||
"Position": 367.0
|
||||
}, {
|
||||
"StartTime": 1687.0,
|
||||
"Position": 374.159973
|
||||
}, {
|
||||
"StartTime": 1750.0,
|
||||
"Position": 353.0
|
||||
}, {
|
||||
"StartTime": 1812.0,
|
||||
"Position": 329.159973
|
||||
}, {
|
||||
"StartTime": 1875.0,
|
||||
"Position": 288.0
|
||||
}, {
|
||||
"StartTime": 1937.0,
|
||||
"Position": 259.159973
|
||||
}, {
|
||||
"StartTime": 2000.0,
|
||||
"Position": 256.0
|
||||
}, {
|
||||
"StartTime": 2058.0,
|
||||
"Position": 232.44
|
||||
}, {
|
||||
"StartTime": 2116.0,
|
||||
"Position": 222.879974
|
||||
}, {
|
||||
"StartTime": 2174.0,
|
||||
"Position": 185.319992
|
||||
}, {
|
||||
"StartTime": 2232.0,
|
||||
"Position": 177.76001
|
||||
}, {
|
||||
"StartTime": 2290.0,
|
||||
"Position": 162.200012
|
||||
}, {
|
||||
"StartTime": 2348.0,
|
||||
"Position": 158.639984
|
||||
}, {
|
||||
"StartTime": 2406.0,
|
||||
"Position": 111.079994
|
||||
}, {
|
||||
"StartTime": 2500.0,
|
||||
"Position": 96.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 3000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 3000.0,
|
||||
"Position": 18.0
|
||||
}, {
|
||||
"StartTime": 3062.0,
|
||||
"Position": 482.0
|
||||
}, {
|
||||
"StartTime": 3125.0,
|
||||
"Position": 243.0
|
||||
}, {
|
||||
"StartTime": 3187.0,
|
||||
"Position": 332.0
|
||||
}, {
|
||||
"StartTime": 3250.0,
|
||||
"Position": 477.0
|
||||
}, {
|
||||
"StartTime": 3312.0,
|
||||
"Position": 376.0
|
||||
}, {
|
||||
"StartTime": 3375.0,
|
||||
"Position": 104.0
|
||||
}, {
|
||||
"StartTime": 3437.0,
|
||||
"Position": 156.0
|
||||
}, {
|
||||
"StartTime": 3500.0,
|
||||
"Position": 135.0
|
||||
}, {
|
||||
"StartTime": 3562.0,
|
||||
"Position": 256.0
|
||||
}, {
|
||||
"StartTime": 3625.0,
|
||||
"Position": 360.0
|
||||
}, {
|
||||
"StartTime": 3687.0,
|
||||
"Position": 199.0
|
||||
}, {
|
||||
"StartTime": 3750.0,
|
||||
"Position": 239.0
|
||||
}, {
|
||||
"StartTime": 3812.0,
|
||||
"Position": 326.0
|
||||
}, {
|
||||
"StartTime": 3875.0,
|
||||
"Position": 393.0
|
||||
}, {
|
||||
"StartTime": 3937.0,
|
||||
"Position": 470.0
|
||||
}, {
|
||||
"StartTime": 4000.0,
|
||||
"Position": 136.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 4500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 4500.0,
|
||||
"Position": 317.0
|
||||
}, {
|
||||
"StartTime": 4562.0,
|
||||
"Position": 354.0
|
||||
}, {
|
||||
"StartTime": 4625.0,
|
||||
"Position": 414.0
|
||||
}, {
|
||||
"StartTime": 4687.0,
|
||||
"Position": 39.0
|
||||
}, {
|
||||
"StartTime": 4750.0,
|
||||
"Position": 172.0
|
||||
}, {
|
||||
"StartTime": 4812.0,
|
||||
"Position": 479.0
|
||||
}, {
|
||||
"StartTime": 4875.0,
|
||||
"Position": 18.0
|
||||
}, {
|
||||
"StartTime": 4937.0,
|
||||
"Position": 151.0
|
||||
}, {
|
||||
"StartTime": 5000.0,
|
||||
"Position": 342.0
|
||||
}, {
|
||||
"StartTime": 5062.0,
|
||||
"Position": 400.0
|
||||
}, {
|
||||
"StartTime": 5125.0,
|
||||
"Position": 420.0
|
||||
}, {
|
||||
"StartTime": 5187.0,
|
||||
"Position": 90.0
|
||||
}, {
|
||||
"StartTime": 5250.0,
|
||||
"Position": 220.0
|
||||
}, {
|
||||
"StartTime": 5312.0,
|
||||
"Position": 80.0
|
||||
}, {
|
||||
"StartTime": 5375.0,
|
||||
"Position": 421.0
|
||||
}, {
|
||||
"StartTime": 5437.0,
|
||||
"Position": 473.0
|
||||
}, {
|
||||
"StartTime": 5500.0,
|
||||
"Position": 97.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 6000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 6000.0,
|
||||
"Position": 105.0
|
||||
}, {
|
||||
"StartTime": 6062.0,
|
||||
"Position": 249.0
|
||||
}, {
|
||||
"StartTime": 6125.0,
|
||||
"Position": 163.0
|
||||
}, {
|
||||
"StartTime": 6187.0,
|
||||
"Position": 194.0
|
||||
}, {
|
||||
"StartTime": 6250.0,
|
||||
"Position": 106.0
|
||||
}, {
|
||||
"StartTime": 6312.0,
|
||||
"Position": 212.0
|
||||
}, {
|
||||
"StartTime": 6375.0,
|
||||
"Position": 257.0
|
||||
}, {
|
||||
"StartTime": 6437.0,
|
||||
"Position": 461.0
|
||||
}, {
|
||||
"StartTime": 6500.0,
|
||||
"Position": 79.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 7000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 7000.0,
|
||||
"Position": 256.0
|
||||
}, {
|
||||
"StartTime": 7062.0,
|
||||
"Position": 294.84
|
||||
}, {
|
||||
"StartTime": 7125.0,
|
||||
"Position": 279.0
|
||||
}, {
|
||||
"StartTime": 7187.0,
|
||||
"Position": 309.84
|
||||
}, {
|
||||
"StartTime": 7250.0,
|
||||
"Position": 336.0
|
||||
}, {
|
||||
"StartTime": 7312.0,
|
||||
"Position": 322.16
|
||||
}, {
|
||||
"StartTime": 7375.0,
|
||||
"Position": 308.0
|
||||
}, {
|
||||
"StartTime": 7437.0,
|
||||
"Position": 263.16
|
||||
}, {
|
||||
"StartTime": 7500.0,
|
||||
"Position": 256.0
|
||||
}, {
|
||||
"StartTime": 7562.0,
|
||||
"Position": 261.84
|
||||
}, {
|
||||
"StartTime": 7625.0,
|
||||
"Position": 277.0
|
||||
}, {
|
||||
"StartTime": 7687.0,
|
||||
"Position": 318.84
|
||||
}, {
|
||||
"StartTime": 7750.0,
|
||||
"Position": 336.0
|
||||
}, {
|
||||
"StartTime": 7803.0,
|
||||
"Position": 305.04
|
||||
}, {
|
||||
"StartTime": 7857.0,
|
||||
"Position": 307.76
|
||||
}, {
|
||||
"StartTime": 7910.0,
|
||||
"Position": 297.8
|
||||
}, {
|
||||
"StartTime": 8000.0,
|
||||
"Position": 256.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 8500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 8500.0,
|
||||
"Position": 32.0
|
||||
}, {
|
||||
"StartTime": 8562.0,
|
||||
"Position": 22.8515015
|
||||
}, {
|
||||
"StartTime": 8625.0,
|
||||
"Position": 28.5659637
|
||||
}, {
|
||||
"StartTime": 8687.0,
|
||||
"Position": 50.3433228
|
||||
}, {
|
||||
"StartTime": 8750.0,
|
||||
"Position": 56.58974
|
||||
}, {
|
||||
"StartTime": 8812.0,
|
||||
"Position": 64.23422
|
||||
}, {
|
||||
"StartTime": 8875.0,
|
||||
"Position": 67.7117844
|
||||
}, {
|
||||
"StartTime": 8937.0,
|
||||
"Position": 90.52607
|
||||
}, {
|
||||
"StartTime": 9000.0,
|
||||
"Position": 101.81015
|
||||
}, {
|
||||
"StartTime": 9062.0,
|
||||
"Position": 113.478188
|
||||
}, {
|
||||
"StartTime": 9125.0,
|
||||
"Position": 159.414444
|
||||
}, {
|
||||
"StartTime": 9187.0,
|
||||
"Position": 155.1861
|
||||
}, {
|
||||
"StartTime": 9250.0,
|
||||
"Position": 179.600418
|
||||
}, {
|
||||
"StartTime": 9312.0,
|
||||
"Position": 212.293015
|
||||
}, {
|
||||
"StartTime": 9375.0,
|
||||
"Position": 197.2076
|
||||
}, {
|
||||
"StartTime": 9437.0,
|
||||
"Position": 243.438324
|
||||
}, {
|
||||
"StartTime": 9500.0,
|
||||
"Position": 237.2304
|
||||
}, {
|
||||
"StartTime": 9562.0,
|
||||
"Position": 241.253983
|
||||
}, {
|
||||
"StartTime": 9625.0,
|
||||
"Position": 258.950623
|
||||
}, {
|
||||
"StartTime": 9687.0,
|
||||
"Position": 253.3786
|
||||
}, {
|
||||
"StartTime": 9750.0,
|
||||
"Position": 270.8865
|
||||
}, {
|
||||
"StartTime": 9812.0,
|
||||
"Position": 244.38974
|
||||
}, {
|
||||
"StartTime": 9875.0,
|
||||
"Position": 242.701874
|
||||
}, {
|
||||
"StartTime": 9937.0,
|
||||
"Position": 256.2331
|
||||
}, {
|
||||
"StartTime": 10000.0,
|
||||
"Position": 270.339874
|
||||
}, {
|
||||
"StartTime": 10062.0,
|
||||
"Position": 275.9349
|
||||
}, {
|
||||
"StartTime": 10125.0,
|
||||
"Position": 297.2969
|
||||
}, {
|
||||
"StartTime": 10187.0,
|
||||
"Position": 307.834137
|
||||
}, {
|
||||
"StartTime": 10250.0,
|
||||
"Position": 321.6449
|
||||
}, {
|
||||
"StartTime": 10312.0,
|
||||
"Position": 357.746338
|
||||
}, {
|
||||
"StartTime": 10375.0,
|
||||
"Position": 358.21875
|
||||
}, {
|
||||
"StartTime": 10437.0,
|
||||
"Position": 394.943
|
||||
}, {
|
||||
"StartTime": 10500.0,
|
||||
"Position": 401.0588
|
||||
}, {
|
||||
"StartTime": 10558.0,
|
||||
"Position": 418.21347
|
||||
}, {
|
||||
"StartTime": 10616.0,
|
||||
"Position": 424.6034
|
||||
}, {
|
||||
"StartTime": 10674.0,
|
||||
"Position": 455.835754
|
||||
}, {
|
||||
"StartTime": 10732.0,
|
||||
"Position": 477.5042
|
||||
}, {
|
||||
"StartTime": 10790.0,
|
||||
"Position": 476.290955
|
||||
}, {
|
||||
"StartTime": 10848.0,
|
||||
"Position": 470.943237
|
||||
}, {
|
||||
"StartTime": 10906.0,
|
||||
"Position": 503.3372
|
||||
}, {
|
||||
"StartTime": 10999.0,
|
||||
"Position": 508.166229
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 11500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 11500.0,
|
||||
"Position": 321.0
|
||||
}, {
|
||||
"StartTime": 11562.0,
|
||||
"Position": 17.0
|
||||
}, {
|
||||
"StartTime": 11625.0,
|
||||
"Position": 173.0
|
||||
}, {
|
||||
"StartTime": 11687.0,
|
||||
"Position": 170.0
|
||||
}, {
|
||||
"StartTime": 11750.0,
|
||||
"Position": 447.0
|
||||
}, {
|
||||
"StartTime": 11812.0,
|
||||
"Position": 218.0
|
||||
}, {
|
||||
"StartTime": 11875.0,
|
||||
"Position": 394.0
|
||||
}, {
|
||||
"StartTime": 11937.0,
|
||||
"Position": 46.0
|
||||
}, {
|
||||
"StartTime": 12000.0,
|
||||
"Position": 480.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 12500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 12500.0,
|
||||
"Position": 512.0
|
||||
}, {
|
||||
"StartTime": 12562.0,
|
||||
"Position": 491.3132
|
||||
}, {
|
||||
"StartTime": 12625.0,
|
||||
"Position": 484.3089
|
||||
}, {
|
||||
"StartTime": 12687.0,
|
||||
"Position": 454.6221
|
||||
}, {
|
||||
"StartTime": 12750.0,
|
||||
"Position": 433.617767
|
||||
}, {
|
||||
"StartTime": 12812.0,
|
||||
"Position": 399.930969
|
||||
}, {
|
||||
"StartTime": 12875.0,
|
||||
"Position": 395.926666
|
||||
}, {
|
||||
"StartTime": 12937.0,
|
||||
"Position": 361.239868
|
||||
}, {
|
||||
"StartTime": 13000.0,
|
||||
"Position": 353.235535
|
||||
}, {
|
||||
"StartTime": 13062.0,
|
||||
"Position": 314.548767
|
||||
}, {
|
||||
"StartTime": 13125.0,
|
||||
"Position": 315.544434
|
||||
}, {
|
||||
"StartTime": 13187.0,
|
||||
"Position": 288.857635
|
||||
}, {
|
||||
"StartTime": 13250.0,
|
||||
"Position": 254.853333
|
||||
}, {
|
||||
"StartTime": 13312.0,
|
||||
"Position": 239.166534
|
||||
}, {
|
||||
"StartTime": 13375.0,
|
||||
"Position": 240.1622
|
||||
}, {
|
||||
"StartTime": 13437.0,
|
||||
"Position": 212.4754
|
||||
}, {
|
||||
"StartTime": 13500.0,
|
||||
"Position": 194.471069
|
||||
}, {
|
||||
"StartTime": 13562.0,
|
||||
"Position": 161.784271
|
||||
}, {
|
||||
"StartTime": 13625.0,
|
||||
"Position": 145.779968
|
||||
}, {
|
||||
"StartTime": 13687.0,
|
||||
"Position": 129.09314
|
||||
}, {
|
||||
"StartTime": 13750.0,
|
||||
"Position": 104.088837
|
||||
}, {
|
||||
"StartTime": 13812.0,
|
||||
"Position": 95.40204
|
||||
}, {
|
||||
"StartTime": 13875.0,
|
||||
"Position": 61.3977356
|
||||
}, {
|
||||
"StartTime": 13937.0,
|
||||
"Position": 56.710907
|
||||
}, {
|
||||
"StartTime": 14000.0,
|
||||
"Position": 35.7066345
|
||||
}, {
|
||||
"StartTime": 14062.0,
|
||||
"Position": 5.019806
|
||||
}, {
|
||||
"StartTime": 14125.0,
|
||||
"Position": 0.0
|
||||
}, {
|
||||
"StartTime": 14187.0,
|
||||
"Position": 39.7696266
|
||||
}, {
|
||||
"StartTime": 14250.0,
|
||||
"Position": 23.0119171
|
||||
}, {
|
||||
"StartTime": 14312.0,
|
||||
"Position": 75.94882
|
||||
}, {
|
||||
"StartTime": 14375.0,
|
||||
"Position": 98.19112
|
||||
}, {
|
||||
"StartTime": 14437.0,
|
||||
"Position": 82.12803
|
||||
}, {
|
||||
"StartTime": 14500.0,
|
||||
"Position": 118.370323
|
||||
}, {
|
||||
"StartTime": 14562.0,
|
||||
"Position": 149.307236
|
||||
}, {
|
||||
"StartTime": 14625.0,
|
||||
"Position": 168.549515
|
||||
}, {
|
||||
"StartTime": 14687.0,
|
||||
"Position": 190.486435
|
||||
}, {
|
||||
"StartTime": 14750.0,
|
||||
"Position": 186.728714
|
||||
}, {
|
||||
"StartTime": 14812.0,
|
||||
"Position": 199.665634
|
||||
}, {
|
||||
"StartTime": 14875.0,
|
||||
"Position": 228.907928
|
||||
}, {
|
||||
"StartTime": 14937.0,
|
||||
"Position": 264.844849
|
||||
}, {
|
||||
"StartTime": 15000.0,
|
||||
"Position": 271.087128
|
||||
}, {
|
||||
"StartTime": 15062.0,
|
||||
"Position": 290.024017
|
||||
}, {
|
||||
"StartTime": 15125.0,
|
||||
"Position": 302.266327
|
||||
}, {
|
||||
"StartTime": 15187.0,
|
||||
"Position": 344.203247
|
||||
}, {
|
||||
"StartTime": 15250.0,
|
||||
"Position": 356.445526
|
||||
}, {
|
||||
"StartTime": 15312.0,
|
||||
"Position": 359.382446
|
||||
}, {
|
||||
"StartTime": 15375.0,
|
||||
"Position": 401.624725
|
||||
}, {
|
||||
"StartTime": 15437.0,
|
||||
"Position": 388.561646
|
||||
}, {
|
||||
"StartTime": 15500.0,
|
||||
"Position": 423.803925
|
||||
}, {
|
||||
"StartTime": 15562.0,
|
||||
"Position": 425.740845
|
||||
}, {
|
||||
"StartTime": 15625.0,
|
||||
"Position": 449.983124
|
||||
}, {
|
||||
"StartTime": 15687.0,
|
||||
"Position": 468.920044
|
||||
}, {
|
||||
"StartTime": 15750.0,
|
||||
"Position": 492.162323
|
||||
}, {
|
||||
"StartTime": 15812.0,
|
||||
"Position": 506.784332
|
||||
}, {
|
||||
"StartTime": 15875.0,
|
||||
"Position": 474.226227
|
||||
}, {
|
||||
"StartTime": 15937.0,
|
||||
"Position": 482.978638
|
||||
}, {
|
||||
"StartTime": 16000.0,
|
||||
"Position": 446.420532
|
||||
}, {
|
||||
"StartTime": 16058.0,
|
||||
"Position": 418.4146
|
||||
}, {
|
||||
"StartTime": 16116.0,
|
||||
"Position": 425.408844
|
||||
}, {
|
||||
"StartTime": 16174.0,
|
||||
"Position": 383.402924
|
||||
}, {
|
||||
"StartTime": 16232.0,
|
||||
"Position": 363.397156
|
||||
}, {
|
||||
"StartTime": 16290.0,
|
||||
"Position": 343.391235
|
||||
}, {
|
||||
"StartTime": 16348.0,
|
||||
"Position": 328.385468
|
||||
}, {
|
||||
"StartTime": 16406.0,
|
||||
"Position": 322.3797
|
||||
}, {
|
||||
"StartTime": 16500.0,
|
||||
"Position": 291.1977
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 17000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 17000.0,
|
||||
"Position": 256.0
|
||||
}, {
|
||||
"StartTime": 17062.0,
|
||||
"Position": 228.16
|
||||
}, {
|
||||
"StartTime": 17125.0,
|
||||
"Position": 234.0
|
||||
}, {
|
||||
"StartTime": 17187.0,
|
||||
"Position": 202.16
|
||||
}, {
|
||||
"StartTime": 17250.0,
|
||||
"Position": 176.0
|
||||
}, {
|
||||
"StartTime": 17312.0,
|
||||
"Position": 210.84
|
||||
}, {
|
||||
"StartTime": 17375.0,
|
||||
"Position": 221.0
|
||||
}, {
|
||||
"StartTime": 17437.0,
|
||||
"Position": 219.84
|
||||
}, {
|
||||
"StartTime": 17500.0,
|
||||
"Position": 256.0
|
||||
}, {
|
||||
"StartTime": 17562.0,
|
||||
"Position": 219.16
|
||||
}, {
|
||||
"StartTime": 17625.0,
|
||||
"Position": 228.0
|
||||
}, {
|
||||
"StartTime": 17687.0,
|
||||
"Position": 203.16
|
||||
}, {
|
||||
"StartTime": 17750.0,
|
||||
"Position": 176.0
|
||||
}, {
|
||||
"StartTime": 17803.0,
|
||||
"Position": 174.959991
|
||||
}, {
|
||||
"StartTime": 17857.0,
|
||||
"Position": 214.23999
|
||||
}, {
|
||||
"StartTime": 17910.0,
|
||||
"Position": 228.200012
|
||||
}, {
|
||||
"StartTime": 18000.0,
|
||||
"Position": 256.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 18500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 18500.0,
|
||||
"Position": 362.0
|
||||
}, {
|
||||
"StartTime": 18559.0,
|
||||
"Position": 249.0
|
||||
}, {
|
||||
"StartTime": 18618.0,
|
||||
"Position": 357.0
|
||||
}, {
|
||||
"StartTime": 18678.0,
|
||||
"Position": 167.0
|
||||
}, {
|
||||
"StartTime": 18737.0,
|
||||
"Position": 477.0
|
||||
}, {
|
||||
"StartTime": 18796.0,
|
||||
"Position": 411.0
|
||||
}, {
|
||||
"StartTime": 18856.0,
|
||||
"Position": 254.0
|
||||
}, {
|
||||
"StartTime": 18915.0,
|
||||
"Position": 308.0
|
||||
}, {
|
||||
"StartTime": 18975.0,
|
||||
"Position": 399.0
|
||||
}, {
|
||||
"StartTime": 19034.0,
|
||||
"Position": 176.0
|
||||
}, {
|
||||
"StartTime": 19093.0,
|
||||
"Position": 14.0
|
||||
}, {
|
||||
"StartTime": 19153.0,
|
||||
"Position": 258.0
|
||||
}, {
|
||||
"StartTime": 19212.0,
|
||||
"Position": 221.0
|
||||
}, {
|
||||
"StartTime": 19271.0,
|
||||
"Position": 481.0
|
||||
}, {
|
||||
"StartTime": 19331.0,
|
||||
"Position": 92.0
|
||||
}, {
|
||||
"StartTime": 19390.0,
|
||||
"Position": 211.0
|
||||
}, {
|
||||
"StartTime": 19450.0,
|
||||
"Position": 135.0
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 19875.0,
|
||||
"Objects": [{
|
||||
"StartTime": 19875.0,
|
||||
"Position": 216.0
|
||||
}, {
|
||||
"StartTime": 19937.0,
|
||||
"Position": 215.307053
|
||||
}, {
|
||||
"StartTime": 20000.0,
|
||||
"Position": 236.036865
|
||||
}, {
|
||||
"StartTime": 20062.0,
|
||||
"Position": 236.312088
|
||||
}, {
|
||||
"StartTime": 20125.0,
|
||||
"Position": 235.838928
|
||||
}, {
|
||||
"StartTime": 20187.0,
|
||||
"Position": 269.9743
|
||||
}, {
|
||||
"StartTime": 20250.0,
|
||||
"Position": 285.999146
|
||||
}, {
|
||||
"StartTime": 20312.0,
|
||||
"Position": 283.669067
|
||||
}, {
|
||||
"StartTime": 20375.0,
|
||||
"Position": 317.446747
|
||||
}, {
|
||||
"StartTime": 20437.0,
|
||||
"Position": 330.750275
|
||||
}, {
|
||||
"StartTime": 20500.0,
|
||||
"Position": 344.0156
|
||||
}, {
|
||||
"StartTime": 20562.0,
|
||||
"Position": 318.472168
|
||||
}, {
|
||||
"StartTime": 20625.0,
|
||||
"Position": 309.165466
|
||||
}, {
|
||||
"StartTime": 20687.0,
|
||||
"Position": 317.044617
|
||||
}, {
|
||||
"StartTime": 20750.0,
|
||||
"Position": 280.457367
|
||||
}, {
|
||||
"StartTime": 20812.0,
|
||||
"Position": 272.220581
|
||||
}, {
|
||||
"StartTime": 20875.0,
|
||||
"Position": 270.3294
|
||||
}, {
|
||||
"StartTime": 20937.0,
|
||||
"Position": 262.57605
|
||||
}, {
|
||||
"StartTime": 21000.0,
|
||||
"Position": 244.803329
|
||||
}, {
|
||||
"StartTime": 21062.0,
|
||||
"Position": 215.958359
|
||||
}, {
|
||||
"StartTime": 21125.0,
|
||||
"Position": 177.79332
|
||||
}, {
|
||||
"StartTime": 21187.0,
|
||||
"Position": 190.948349
|
||||
}, {
|
||||
"StartTime": 21250.0,
|
||||
"Position": 158.78334
|
||||
}, {
|
||||
"StartTime": 21312.0,
|
||||
"Position": 136.93837
|
||||
}, {
|
||||
"StartTime": 21375.0,
|
||||
"Position": 119.121056
|
||||
}, {
|
||||
"StartTime": 21437.0,
|
||||
"Position": 132.387573
|
||||
}, {
|
||||
"StartTime": 21500.0,
|
||||
"Position": 124.503014
|
||||
}, {
|
||||
"StartTime": 21562.0,
|
||||
"Position": 118.749374
|
||||
}, {
|
||||
"StartTime": 21625.0,
|
||||
"Position": 123.165535
|
||||
}, {
|
||||
"StartTime": 21687.0,
|
||||
"Position": 96.02999
|
||||
}, {
|
||||
"StartTime": 21750.0,
|
||||
"Position": 118.547928
|
||||
}, {
|
||||
"StartTime": 21812.0,
|
||||
"Position": 128.856232
|
||||
}, {
|
||||
"StartTime": 21875.0,
|
||||
"Position": 124.28746
|
||||
}, {
|
||||
"StartTime": 21937.0,
|
||||
"Position": 150.754929
|
||||
}, {
|
||||
"StartTime": 22000.0,
|
||||
"Position": 149.528732
|
||||
}, {
|
||||
"StartTime": 22062.0,
|
||||
"Position": 145.1691
|
||||
}, {
|
||||
"StartTime": 22125.0,
|
||||
"Position": 182.802155
|
||||
}, {
|
||||
"StartTime": 22187.0,
|
||||
"Position": 178.6452
|
||||
}, {
|
||||
"StartTime": 22250.0,
|
||||
"Position": 213.892181
|
||||
}, {
|
||||
"StartTime": 22312.0,
|
||||
"Position": 218.713028
|
||||
}, {
|
||||
"StartTime": 22375.0,
|
||||
"Position": 240.4715
|
||||
}, {
|
||||
"StartTime": 22437.0,
|
||||
"Position": 239.371887
|
||||
}, {
|
||||
"StartTime": 22500.0,
|
||||
"Position": 261.907257
|
||||
}, {
|
||||
"StartTime": 22562.0,
|
||||
"Position": 314.353119
|
||||
}, {
|
||||
"StartTime": 22625.0,
|
||||
"Position": 299.273376
|
||||
}, {
|
||||
"StartTime": 22687.0,
|
||||
"Position": 356.98288
|
||||
}, {
|
||||
"StartTime": 22750.0,
|
||||
"Position": 339.078552
|
||||
}, {
|
||||
"StartTime": 22812.0,
|
||||
"Position": 377.8958
|
||||
}, {
|
||||
"StartTime": 22875.0,
|
||||
"Position": 398.054047
|
||||
}, {
|
||||
"StartTime": 22937.0,
|
||||
"Position": 398.739441
|
||||
}, {
|
||||
"StartTime": 23000.0,
|
||||
"Position": 407.178467
|
||||
}, {
|
||||
"StartTime": 23062.0,
|
||||
"Position": 444.8687
|
||||
}, {
|
||||
"StartTime": 23125.0,
|
||||
"Position": 417.069977
|
||||
}, {
|
||||
"StartTime": 23187.0,
|
||||
"Position": 454.688477
|
||||
}, {
|
||||
"StartTime": 23250.0,
|
||||
"Position": 428.9612
|
||||
}, {
|
||||
"StartTime": 23312.0,
|
||||
"Position": 441.92807
|
||||
}, {
|
||||
"StartTime": 23375.0,
|
||||
"Position": 439.749878
|
||||
}, {
|
||||
"StartTime": 23433.0,
|
||||
"Position": 455.644684
|
||||
}, {
|
||||
"StartTime": 23491.0,
|
||||
"Position": 440.7359
|
||||
}, {
|
||||
"StartTime": 23549.0,
|
||||
"Position": 430.0944
|
||||
}, {
|
||||
"StartTime": 23607.0,
|
||||
"Position": 420.796173
|
||||
}, {
|
||||
"StartTime": 23665.0,
|
||||
"Position": 435.897461
|
||||
}, {
|
||||
"StartTime": 23723.0,
|
||||
"Position": 418.462555
|
||||
}, {
|
||||
"StartTime": 23781.0,
|
||||
"Position": 405.53775
|
||||
}, {
|
||||
"StartTime": 23874.0,
|
||||
"Position": 408.720825
|
||||
}]
|
||||
}]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
osu file format v14
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:6
|
||||
CircleSize:4
|
||||
OverallDifficulty:7
|
||||
ApproachRate:8.3
|
||||
SliderMultiplier:1.6
|
||||
SliderTickRate:1
|
||||
|
||||
[TimingPoints]
|
||||
500,500,4,2,1,50,1,0
|
||||
13426,-100,4,3,1,45,0,0
|
||||
14884,-100,4,2,1,50,0,0
|
||||
|
||||
[HitObjects]
|
||||
96,192,500,6,0,L|416:192,2,320
|
||||
256,192,3000,12,0,4000,0:0:0:0:
|
||||
256,192,4500,12,0,5500,0:0:0:0:
|
||||
256,192,6000,12,0,6500,0:0:0:0:
|
||||
256,128,7000,6,0,L|352:128,4,80
|
||||
32,192,8500,6,0,B|32:384|256:384|256:192|256:192|256:0|512:0|512:192,1,800
|
||||
256,192,11500,12,0,12000,0:0:0:0:
|
||||
512,320,12500,6,0,B|0:256|0:256|512:96|512:96|256:32,1,1280
|
||||
256,256,17000,6,0,L|160:256,4,80
|
||||
256,192,18500,12,0,19450,0:0:0:0:
|
||||
216,231,19875,6,0,B|216:135|280:135|344:135|344:199|344:263|248:327|248:327|120:327|120:327|56:39|408:39|408:39|472:150|408:342,1,1280
|
||||
@@ -24,17 +24,13 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
||||
switch (obj)
|
||||
{
|
||||
case JuiceStream stream:
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
|
||||
foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
case BananaShower shower:
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
|
||||
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
case Fruit _:
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// 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.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||
|
||||
[TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2149")]
|
||||
public new void Test(string name)
|
||||
{
|
||||
base.Test(name);
|
||||
}
|
||||
|
||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||
{
|
||||
if (hitObject is JuiceStream stream)
|
||||
{
|
||||
foreach (var nested in stream.NestedHitObjects)
|
||||
{
|
||||
yield return new ConvertValue
|
||||
{
|
||||
StartTime = nested.StartTime,
|
||||
Position = ((CatchHitObject)nested).X * CatchPlayfield.BASE_WIDTH
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new ConvertValue
|
||||
{
|
||||
StartTime = hitObject.StartTime,
|
||||
Position = ((CatchHitObject)hitObject).X * CatchPlayfield.BASE_WIDTH
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new CatchBeatmapConverter();
|
||||
}
|
||||
|
||||
public struct ConvertValue : IEquatable<ConvertValue>
|
||||
{
|
||||
/// <summary>
|
||||
/// A sane value to account for osu!stable using ints everwhere.
|
||||
/// </summary>
|
||||
private const float conversion_lenience = 2;
|
||||
|
||||
public double StartTime;
|
||||
public float Position;
|
||||
|
||||
public bool Equals(ConvertValue other)
|
||||
=> Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience)
|
||||
&& Precision.AlmostEquals(Position, other.Position, conversion_lenience);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ using osu.Game.Rulesets.Catch.UI;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseBananaShower : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
@@ -29,16 +28,14 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
}
|
||||
|
||||
protected override Beatmap CreateBeatmap()
|
||||
protected override Beatmap CreateBeatmap(Ruleset ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 6,
|
||||
}
|
||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
|
||||
Ruleset = ruleset.RulesetInfo
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using NUnit.Framework;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public TestCaseCatchPlayer() : base(new CatchRuleset())
|
||||
|
||||
@@ -8,7 +8,6 @@ using osu.Game.Rulesets.Catch.Objects;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public TestCaseCatchStacker()
|
||||
@@ -16,19 +15,18 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
}
|
||||
|
||||
protected override Beatmap CreateBeatmap()
|
||||
protected override Beatmap CreateBeatmap(Ruleset ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 6,
|
||||
}
|
||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
|
||||
Ruleset = ruleset.RulesetInfo
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ using osu.Game.Tests.Visual;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseCatcherArea : OsuTestCase
|
||||
{
|
||||
private RulesetInfo catchRuleset;
|
||||
|
||||
@@ -16,7 +16,7 @@ using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
[TestFixture]
|
||||
public class TestCaseFruitObjects : OsuTestCase
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
|
||||
@@ -8,7 +8,6 @@ using osu.Game.Rulesets.Catch.Objects;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public TestCaseHyperdash()
|
||||
@@ -16,9 +15,10 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
}
|
||||
|
||||
protected override Beatmap CreateBeatmap()
|
||||
protected override Beatmap CreateBeatmap(Ruleset ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap();
|
||||
var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
|
||||
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
if (i % 5 < 3)
|
||||
|
||||
@@ -5,7 +5,7 @@ using NUnit.Framework;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
[TestFixture]
|
||||
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
|
||||
{
|
||||
public TestCasePerformancePoints()
|
||||
|
||||
@@ -35,10 +35,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
ScaledContent.AddRange(new Drawable[]
|
||||
{
|
||||
content = new Container<Drawable>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
explodingFruitContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@@ -49,7 +45,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
ExplodingFruitTarget = explodingFruitContainer,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
}
|
||||
},
|
||||
content = new Container<Drawable>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Input.Handlers;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
@@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
|
||||
|
||||
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||
|
||||
protected override BeatmapProcessor<CatchHitObject> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatcherArea : Container, IKeyBindingHandler<CatchAction>
|
||||
public class CatcherArea : Container
|
||||
{
|
||||
public const float CATCHER_SIZE = 172;
|
||||
|
||||
@@ -84,16 +84,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnPressed(CatchAction action)
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
if (action != CatchAction.PositionUpdate) return false;
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
CatchFramedReplayInputHandler.CatchReplayState state = (CatchFramedReplayInputHandler.CatchReplayState)GetContainingInputManager().CurrentState;
|
||||
var state = GetContainingInputManager().CurrentState as CatchFramedReplayInputHandler.CatchReplayState;
|
||||
|
||||
if (state.CatcherX.HasValue)
|
||||
if (state?.CatcherX != null)
|
||||
MovableCatcher.X = state.CatcherX.Value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnReleased(CatchAction action) => false;
|
||||
|
||||
@@ -32,14 +32,30 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.11\lib\net45\OpenTK.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections" />
|
||||
<Reference Include="System.Core" />
|
||||
@@ -79,6 +95,7 @@
|
||||
<Compile Include="Objects\Fruit.cs" />
|
||||
<Compile Include="Objects\TinyDroplet.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Tests\CatchBeatmapConversionTest.cs" />
|
||||
<Compile Include="Tests\TestCaseBananaShower.cs" />
|
||||
<Compile Include="Tests\TestCaseCatcherArea.cs" />
|
||||
<Compile Include="Tests\TestCaseCatchStacker.cs" />
|
||||
@@ -112,12 +129,20 @@
|
||||
<ItemGroup>
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" />
|
||||
<EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
|
||||
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
|
||||
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
|
||||
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
|
||||
</Project>
|
||||
@@ -1,5 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.8.1" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
|
||||
</packages>
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// <summary>
|
||||
/// The definitions for each stage in a <see cref="ManiaPlayfield"/>.
|
||||
/// </summary>
|
||||
public readonly List<StageDefinition> Stages = new List<StageDefinition>();
|
||||
public List<StageDefinition> Stages = new List<StageDefinition>();
|
||||
|
||||
/// <summary>
|
||||
/// Total number of columns represented by all stages in this <see cref="ManiaBeatmap"/>.
|
||||
@@ -24,10 +24,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ManiaBeatmap"/>.
|
||||
/// </summary>
|
||||
/// <param name="initialStage">The initial stage.</param>
|
||||
public ManiaBeatmap(StageDefinition initialStage)
|
||||
/// <param name="defaultStage">The initial stages.</param>
|
||||
public ManiaBeatmap(StageDefinition defaultStage)
|
||||
{
|
||||
Stages.Add(initialStage);
|
||||
Stages.Add(defaultStage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -216,7 +215,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
if (curveData == null)
|
||||
return HitObject.Samples;
|
||||
|
||||
double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.RepeatCount;
|
||||
double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.SpanCount();
|
||||
|
||||
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||
return curveData.RepeatSamples[index];
|
||||
|
||||
+26
-23
@@ -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;
|
||||
@@ -25,39 +26,39 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
private readonly double endTime;
|
||||
private readonly double segmentDuration;
|
||||
private readonly int repeatCount;
|
||||
private readonly int spanCount;
|
||||
|
||||
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;
|
||||
var repeatsData = hitObject as IHasRepeats;
|
||||
|
||||
repeatCount = repeatsData?.RepeatCount ?? 1;
|
||||
spanCount = repeatsData?.SpanCount() ?? 1;
|
||||
|
||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
||||
|
||||
// The true distance, accounting for any repeats
|
||||
double distance = (distanceData?.Distance ?? 0) * repeatCount;
|
||||
double distance = (distanceData?.Distance ?? 0) * spanCount;
|
||||
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
||||
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
||||
// The duration of the osu! hit object
|
||||
double osuDuration = distance / osuVelocity;
|
||||
|
||||
endTime = hitObject.StartTime + osuDuration;
|
||||
segmentDuration = (endTime - HitObject.StartTime) / repeatCount;
|
||||
segmentDuration = (endTime - HitObject.StartTime) / spanCount;
|
||||
}
|
||||
|
||||
public override Pattern Generate()
|
||||
{
|
||||
if (repeatCount > 1)
|
||||
if (spanCount > 1)
|
||||
{
|
||||
if (segmentDuration <= 90)
|
||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||
@@ -65,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
if (segmentDuration <= 120)
|
||||
{
|
||||
convertType |= PatternType.ForceNotStack;
|
||||
return generateRandomNotes(HitObject.StartTime, repeatCount + 1);
|
||||
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
||||
}
|
||||
|
||||
if (segmentDuration <= 160)
|
||||
@@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
if (duration >= 4000)
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
||||
|
||||
if (segmentDuration > 400 && repeatCount < TotalColumns - 1 - RandomStart)
|
||||
if (segmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
||||
return generateTiledHoldNotes(HitObject.StartTime);
|
||||
|
||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||
@@ -212,7 +213,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
bool increasing = Random.NextDouble() > 0.5;
|
||||
|
||||
for (int i = 0; i <= repeatCount; i++)
|
||||
for (int i = 0; i <= spanCount; i++)
|
||||
{
|
||||
addToPattern(pattern, column, startTime, startTime);
|
||||
startTime += segmentDuration;
|
||||
@@ -262,7 +263,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int interval = Random.Next(1, TotalColumns - (legacy ? 1 : 0));
|
||||
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
for (int i = 0; i <= repeatCount; i++)
|
||||
for (int i = 0; i <= spanCount; i++)
|
||||
{
|
||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -350,7 +351,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
var pattern = new Pattern();
|
||||
|
||||
int columnRepeat = Math.Min(repeatCount, TotalColumns);
|
||||
int columnRepeat = Math.Min(spanCount, TotalColumns);
|
||||
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
@@ -396,20 +397,22 @@ 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 <= repeatCount; i++)
|
||||
for (int i = 0; i <= spanCount; i++)
|
||||
{
|
||||
if (!(ignoreHead && startTime == HitObject.StartTime))
|
||||
{
|
||||
@@ -442,7 +445,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
if (curveData == null)
|
||||
return HitObject.Samples;
|
||||
|
||||
double segmentTime = (endTime - HitObject.StartTime) / repeatCount;
|
||||
double segmentTime = (endTime - HitObject.StartTime) / spanCount;
|
||||
|
||||
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||
return curveData.RepeatSamples[index];
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -14,5 +14,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// The number of <see cref="Column"/>s which this stage contains.
|
||||
/// </summary>
|
||||
public int Columns;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the column index is a special column for this stage.
|
||||
/// </summary>
|
||||
/// <param name="column">The 0-based column index.</param>
|
||||
/// <returns>Whether the column is a special column.</returns>
|
||||
public bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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.Configuration.Tracking;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Configuration
|
||||
{
|
||||
public class ManiaConfigManager : RulesetConfigManager<ManiaSetting>
|
||||
{
|
||||
public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant)
|
||||
: base(settings, ruleset, variant)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
base.InitialiseDefaults();
|
||||
|
||||
Set(ManiaSetting.ScrollTime, 1500.0, 50.0, 10000.0, 50.0);
|
||||
}
|
||||
|
||||
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||
{
|
||||
new TrackedSetting<double>(ManiaSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms"))
|
||||
};
|
||||
}
|
||||
|
||||
public enum ManiaSetting
|
||||
{
|
||||
ScrollTime
|
||||
}
|
||||
}
|
||||
@@ -1,200 +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.Beatmaps;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
public class HitWindows
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// PERFECT hit window at OD = 10.
|
||||
/// </summary>
|
||||
private const double perfect_min = 27.8;
|
||||
/// <summary>
|
||||
/// PERFECT hit window at OD = 5.
|
||||
/// </summary>
|
||||
private const double perfect_mid = 38.8;
|
||||
/// <summary>
|
||||
/// PERFECT hit window at OD = 0.
|
||||
/// </summary>
|
||||
private const double perfect_max = 44.8;
|
||||
|
||||
/// <summary>
|
||||
/// GREAT hit window at OD = 10.
|
||||
/// </summary>
|
||||
private const double great_min = 68;
|
||||
/// <summary>
|
||||
/// GREAT hit window at OD = 5.
|
||||
/// </summary>
|
||||
private const double great_mid = 98;
|
||||
/// <summary>
|
||||
/// GREAT hit window at OD = 0.
|
||||
/// </summary>
|
||||
private const double great_max = 128;
|
||||
|
||||
/// <summary>
|
||||
/// GOOD hit window at OD = 10.
|
||||
/// </summary>
|
||||
private const double good_min = 134;
|
||||
/// <summary>
|
||||
/// GOOD hit window at OD = 5.
|
||||
/// </summary>
|
||||
private const double good_mid = 164;
|
||||
/// <summary>
|
||||
/// GOOD hit window at OD = 0.
|
||||
/// </summary>
|
||||
private const double good_max = 194;
|
||||
|
||||
/// <summary>
|
||||
/// OK hit window at OD = 10.
|
||||
/// </summary>
|
||||
private const double ok_min = 194;
|
||||
/// <summary>
|
||||
/// OK hit window at OD = 5.
|
||||
/// </summary>
|
||||
private const double ok_mid = 224;
|
||||
/// <summary>
|
||||
/// OK hit window at OD = 0.
|
||||
/// </summary>
|
||||
private const double ok_max = 254;
|
||||
|
||||
/// <summary>
|
||||
/// BAD hit window at OD = 10.
|
||||
/// </summary>
|
||||
private const double bad_min = 242;
|
||||
/// <summary>
|
||||
/// BAD hit window at OD = 5.
|
||||
/// </summary>
|
||||
private const double bad_mid = 272;
|
||||
/// <summary>
|
||||
/// BAD hit window at OD = 0.
|
||||
/// </summary>
|
||||
private const double bad_max = 302;
|
||||
|
||||
/// <summary>
|
||||
/// MISS hit window at OD = 10.
|
||||
/// </summary>
|
||||
private const double miss_min = 316;
|
||||
/// <summary>
|
||||
/// MISS hit window at OD = 5.
|
||||
/// </summary>
|
||||
private const double miss_mid = 346;
|
||||
/// <summary>
|
||||
/// MISS hit window at OD = 0.
|
||||
/// </summary>
|
||||
private const double miss_max = 376;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Hit window for a PERFECT hit.
|
||||
/// </summary>
|
||||
public double Perfect = perfect_mid;
|
||||
|
||||
/// <summary>
|
||||
/// Hit window for a GREAT hit.
|
||||
/// </summary>
|
||||
public double Great = great_mid;
|
||||
|
||||
/// <summary>
|
||||
/// Hit window for a GOOD hit.
|
||||
/// </summary>
|
||||
public double Good = good_mid;
|
||||
|
||||
/// <summary>
|
||||
/// Hit window for an OK hit.
|
||||
/// </summary>
|
||||
public double Ok = ok_mid;
|
||||
|
||||
/// <summary>
|
||||
/// Hit window for a BAD hit.
|
||||
/// </summary>
|
||||
public double Bad = bad_mid;
|
||||
|
||||
/// <summary>
|
||||
/// Hit window for a MISS hit.
|
||||
/// </summary>
|
||||
public double Miss = miss_mid;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs default hit windows.
|
||||
/// </summary>
|
||||
public HitWindows()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window.
|
||||
/// </summary>
|
||||
/// <param name="difficulty">The parameter.</param>
|
||||
public HitWindows(double difficulty)
|
||||
{
|
||||
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, perfect_max, perfect_mid, perfect_min);
|
||||
Great = BeatmapDifficulty.DifficultyRange(difficulty, great_max, great_mid, great_min);
|
||||
Good = BeatmapDifficulty.DifficultyRange(difficulty, good_max, good_mid, good_min);
|
||||
Ok = BeatmapDifficulty.DifficultyRange(difficulty, ok_max, ok_mid, ok_min);
|
||||
Bad = BeatmapDifficulty.DifficultyRange(difficulty, bad_max, bad_mid, bad_min);
|
||||
Miss = BeatmapDifficulty.DifficultyRange(difficulty, miss_max, miss_mid, miss_min);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the hit result for a time offset.
|
||||
/// </summary>
|
||||
/// <param name="hitOffset">The time offset.</param>
|
||||
/// <returns>The hit result, or null if the time offset results in a miss.</returns>
|
||||
public HitResult? ResultFor(double hitOffset)
|
||||
{
|
||||
if (hitOffset <= Perfect / 2)
|
||||
return HitResult.Perfect;
|
||||
if (hitOffset <= Great / 2)
|
||||
return HitResult.Great;
|
||||
if (hitOffset <= Good / 2)
|
||||
return HitResult.Good;
|
||||
if (hitOffset <= Ok / 2)
|
||||
return HitResult.Ok;
|
||||
if (hitOffset <= Bad / 2)
|
||||
return HitResult.Meh;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs new hit windows which have been multiplied by a value.
|
||||
/// </summary>
|
||||
/// <param name="windows">The original hit windows.</param>
|
||||
/// <param name="value">The value to multiply each hit window by.</param>
|
||||
public static HitWindows operator *(HitWindows windows, double value)
|
||||
{
|
||||
return new HitWindows
|
||||
{
|
||||
Perfect = windows.Perfect * value,
|
||||
Great = windows.Great * value,
|
||||
Good = windows.Good * value,
|
||||
Ok = windows.Ok * value,
|
||||
Bad = windows.Bad * value,
|
||||
Miss = windows.Miss * value
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs new hit windows which have been divided by a value.
|
||||
/// </summary>
|
||||
/// <param name="windows">The original hit windows.</param>
|
||||
/// <param name="value">The value to divide each hit window by.</param>
|
||||
public static HitWindows operator /(HitWindows windows, double value)
|
||||
{
|
||||
return new HitWindows
|
||||
{
|
||||
Perfect = windows.Perfect / value,
|
||||
Great = windows.Great / value,
|
||||
Good = windows.Good / value,
|
||||
Ok = windows.Ok / value,
|
||||
Bad = windows.Bad / value,
|
||||
Miss = windows.Miss / value
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,142 @@
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania
|
||||
{
|
||||
public class ManiaDifficultyCalculator : DifficultyCalculator<ManiaHitObject>
|
||||
internal class ManiaDifficultyCalculator : DifficultyCalculator<ManiaHitObject>
|
||||
{
|
||||
private const double star_scaling_factor = 0.018;
|
||||
|
||||
/// <summary>
|
||||
/// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size strain_step.
|
||||
/// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
|
||||
/// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage.
|
||||
/// </summary>
|
||||
private const double strain_step = 400;
|
||||
|
||||
/// <summary>
|
||||
/// The weighting of each strain value decays to this number * it's previous value
|
||||
/// </summary>
|
||||
private const double decay_weight = 0.9;
|
||||
|
||||
/// <summary>
|
||||
/// HitObjects are stored as a member variable.
|
||||
/// </summary>
|
||||
private readonly List<ManiaHitObjectDifficulty> difficultyHitObjects = new List<ManiaHitObjectDifficulty>();
|
||||
|
||||
public ManiaDifficultyCalculator(Beatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
|
||||
public ManiaDifficultyCalculator(Beatmap beatmap, Mod[] mods)
|
||||
: base(beatmap, mods)
|
||||
{
|
||||
}
|
||||
|
||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||
{
|
||||
// Fill our custom DifficultyHitObject class, that carries additional information
|
||||
difficultyHitObjects.Clear();
|
||||
|
||||
int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7;
|
||||
|
||||
foreach (var hitObject in Beatmap.HitObjects)
|
||||
difficultyHitObjects.Add(new ManiaHitObjectDifficulty(hitObject, columnCount));
|
||||
|
||||
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
|
||||
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
|
||||
|
||||
if (!calculateStrainValues())
|
||||
return 0;
|
||||
|
||||
double starRating = calculateDifficulty() * star_scaling_factor;
|
||||
|
||||
categoryDifficulty?.Add("Strain", starRating);
|
||||
|
||||
return starRating;
|
||||
}
|
||||
|
||||
private bool calculateStrainValues()
|
||||
{
|
||||
// Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
|
||||
using (List<ManiaHitObjectDifficulty>.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator())
|
||||
{
|
||||
if (!hitObjectsEnumerator.MoveNext())
|
||||
return false;
|
||||
|
||||
ManiaHitObjectDifficulty current = hitObjectsEnumerator.Current;
|
||||
|
||||
// First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject.
|
||||
while (hitObjectsEnumerator.MoveNext())
|
||||
{
|
||||
var next = hitObjectsEnumerator.Current;
|
||||
next?.CalculateStrains(current, TimeRate);
|
||||
current = next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private double calculateDifficulty()
|
||||
{
|
||||
double actualStrainStep = strain_step * TimeRate;
|
||||
|
||||
// Find the highest strain value within each strain step
|
||||
List<double> highestStrains = new List<double>();
|
||||
double intervalEndTime = actualStrainStep;
|
||||
double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
|
||||
|
||||
ManiaHitObjectDifficulty previousHitObject = null;
|
||||
foreach (var hitObject in difficultyHitObjects)
|
||||
{
|
||||
// While we are beyond the current interval push the currently available maximum to our strain list
|
||||
while (hitObject.BaseHitObject.StartTime > intervalEndTime)
|
||||
{
|
||||
highestStrains.Add(maximumStrain);
|
||||
|
||||
// The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay
|
||||
// until the beginning of the next interval.
|
||||
if (previousHitObject == null)
|
||||
{
|
||||
maximumStrain = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double individualDecay = Math.Pow(ManiaHitObjectDifficulty.INDIVIDUAL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
|
||||
double overallDecay = Math.Pow(ManiaHitObjectDifficulty.OVERALL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
|
||||
maximumStrain = previousHitObject.IndividualStrain * individualDecay + previousHitObject.OverallStrain * overallDecay;
|
||||
}
|
||||
|
||||
// Go to the next time interval
|
||||
intervalEndTime += actualStrainStep;
|
||||
}
|
||||
|
||||
// Obtain maximum strain
|
||||
double strain = hitObject.IndividualStrain + hitObject.OverallStrain;
|
||||
maximumStrain = Math.Max(strain, maximumStrain);
|
||||
|
||||
previousHitObject = hitObject;
|
||||
}
|
||||
|
||||
// Build the weighted sum over the highest strains for each interval
|
||||
double difficulty = 0;
|
||||
double weight = 1;
|
||||
highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain.
|
||||
|
||||
foreach (double strain in highestStrains)
|
||||
{
|
||||
difficulty += weight * strain;
|
||||
weight *= decay_weight;
|
||||
}
|
||||
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, beatmap);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,13 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
public enum ManiaAction
|
||||
{
|
||||
[Description("Special")]
|
||||
Special,
|
||||
[Description("Special 1")]
|
||||
Special1 = 1,
|
||||
[Description("Special 2")]
|
||||
Special2,
|
||||
|
||||
// This offsets the start value of normal keys in-case we add more special keys
|
||||
// above at a later time, without breaking replays/configs.
|
||||
[Description("Key 1")]
|
||||
Key1 = 10,
|
||||
[Description("Key 2")]
|
||||
@@ -36,6 +41,24 @@ namespace osu.Game.Rulesets.Mania
|
||||
[Description("Key 8")]
|
||||
Key8,
|
||||
[Description("Key 9")]
|
||||
Key9
|
||||
Key9,
|
||||
[Description("Key 10")]
|
||||
Key10,
|
||||
[Description("Key 11")]
|
||||
Key11,
|
||||
[Description("Key 12")]
|
||||
Key12,
|
||||
[Description("Key 13")]
|
||||
Key13,
|
||||
[Description("Key 14")]
|
||||
Key14,
|
||||
[Description("Key 15")]
|
||||
Key15,
|
||||
[Description("Key 16")]
|
||||
Key16,
|
||||
[Description("Key 17")]
|
||||
Key17,
|
||||
[Description("Key 18")]
|
||||
Key18,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +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 System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Replays.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania
|
||||
{
|
||||
@@ -86,7 +90,8 @@ namespace osu.Game.Rulesets.Mania
|
||||
},
|
||||
},
|
||||
new ManiaModRandom(),
|
||||
new ManiaModKeyCoop(),
|
||||
new ManiaModDualStages(),
|
||||
new ManiaModMirror(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
@@ -108,51 +113,200 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap);
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap, mods);
|
||||
|
||||
public override int LegacyID => 3;
|
||||
public override int? LegacyID => 3;
|
||||
|
||||
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame();
|
||||
|
||||
public ManiaRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<int> AvailableVariants => new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
public override IEnumerable<int> AvailableVariants
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 1; i <= 9; i++)
|
||||
yield return (int)PlayfieldType.Single + i;
|
||||
for (int i = 2; i <= 18; i += 2)
|
||||
yield return (int)PlayfieldType.Dual + i;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
|
||||
{
|
||||
var leftKeys = new[]
|
||||
switch (getPlayfieldType(variant))
|
||||
{
|
||||
InputKey.A,
|
||||
InputKey.S,
|
||||
InputKey.D,
|
||||
InputKey.F
|
||||
};
|
||||
case PlayfieldType.Single:
|
||||
return new VariantMappingGenerator
|
||||
{
|
||||
LeftKeys = new[]
|
||||
{
|
||||
InputKey.A,
|
||||
InputKey.S,
|
||||
InputKey.D,
|
||||
InputKey.F
|
||||
},
|
||||
RightKeys = new[]
|
||||
{
|
||||
InputKey.J,
|
||||
InputKey.K,
|
||||
InputKey.L,
|
||||
InputKey.Semicolon
|
||||
},
|
||||
SpecialKey = InputKey.Space,
|
||||
SpecialAction = ManiaAction.Special1,
|
||||
NormalActionStart = ManiaAction.Key1,
|
||||
}.GenerateKeyBindingsFor(variant, out _);
|
||||
case PlayfieldType.Dual:
|
||||
int keys = getDualStageKeyCount(variant);
|
||||
|
||||
var rightKeys = new[]
|
||||
{
|
||||
InputKey.J,
|
||||
InputKey.K,
|
||||
InputKey.L,
|
||||
InputKey.Semicolon
|
||||
};
|
||||
var stage1Bindings = new VariantMappingGenerator
|
||||
{
|
||||
LeftKeys = new[]
|
||||
{
|
||||
InputKey.Number1,
|
||||
InputKey.Number2,
|
||||
InputKey.Number3,
|
||||
InputKey.Number4,
|
||||
},
|
||||
RightKeys = new[]
|
||||
{
|
||||
InputKey.Z,
|
||||
InputKey.X,
|
||||
InputKey.C,
|
||||
InputKey.V
|
||||
},
|
||||
SpecialKey = InputKey.Tilde,
|
||||
SpecialAction = ManiaAction.Special1,
|
||||
NormalActionStart = ManiaAction.Key1
|
||||
}.GenerateKeyBindingsFor(keys, out var nextNormal);
|
||||
|
||||
ManiaAction currentKey = ManiaAction.Key1;
|
||||
var stage2Bindings = new VariantMappingGenerator
|
||||
{
|
||||
LeftKeys = new[]
|
||||
{
|
||||
InputKey.Number7,
|
||||
InputKey.Number8,
|
||||
InputKey.Number9,
|
||||
InputKey.Number0
|
||||
},
|
||||
RightKeys = new[]
|
||||
{
|
||||
InputKey.O,
|
||||
InputKey.P,
|
||||
InputKey.BracketLeft,
|
||||
InputKey.BracketRight
|
||||
},
|
||||
SpecialKey = InputKey.BackSlash,
|
||||
SpecialAction = ManiaAction.Special2,
|
||||
NormalActionStart = nextNormal
|
||||
}.GenerateKeyBindingsFor(keys, out _);
|
||||
|
||||
var bindings = new List<KeyBinding>();
|
||||
return stage1Bindings.Concat(stage2Bindings);
|
||||
}
|
||||
|
||||
for (int i = leftKeys.Length - variant / 2; i < leftKeys.Length; i++)
|
||||
bindings.Add(new KeyBinding(leftKeys[i], currentKey++));
|
||||
|
||||
for (int i = 0; i < variant / 2; i++)
|
||||
bindings.Add(new KeyBinding(rightKeys[i], currentKey++));
|
||||
|
||||
if (variant % 2 == 1)
|
||||
bindings.Add(new KeyBinding(InputKey.Space, ManiaAction.Special));
|
||||
|
||||
return bindings;
|
||||
return new KeyBinding[0];
|
||||
}
|
||||
|
||||
public override string GetVariantName(int variant) => $"{variant}K";
|
||||
public override string GetVariantName(int variant)
|
||||
{
|
||||
switch (getPlayfieldType(variant))
|
||||
{
|
||||
default:
|
||||
return $"{variant}K";
|
||||
case PlayfieldType.Dual:
|
||||
{
|
||||
var keys = getDualStageKeyCount(variant);
|
||||
return $"{keys}K + {keys}K";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the number of keys for each stage in a <see cref="PlayfieldType.Dual"/> variant.
|
||||
/// </summary>
|
||||
/// <param name="variant">The variant.</param>
|
||||
private int getDualStageKeyCount(int variant) => (variant - (int)PlayfieldType.Dual) / 2;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the <see cref="PlayfieldType"/> that corresponds to a variant value.
|
||||
/// </summary>
|
||||
/// <param name="variant">The variant value.</param>
|
||||
/// <returns>The <see cref="PlayfieldType"/> that corresponds to <paramref name="variant"/>.</returns>
|
||||
private PlayfieldType getPlayfieldType(int variant)
|
||||
{
|
||||
return (PlayfieldType)Enum.GetValues(typeof(PlayfieldType)).Cast<int>().OrderByDescending(i => i).First(v => variant >= v);
|
||||
}
|
||||
|
||||
private class VariantMappingGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// All the <see cref="InputKey"/>s available to the left hand.
|
||||
/// </summary>
|
||||
public InputKey[] LeftKeys;
|
||||
|
||||
/// <summary>
|
||||
/// All the <see cref="InputKey"/>s available to the right hand.
|
||||
/// </summary>
|
||||
public InputKey[] RightKeys;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="InputKey"/> for the special key.
|
||||
/// </summary>
|
||||
public InputKey SpecialKey;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ManiaAction"/> at which the normal columns should begin.
|
||||
/// </summary>
|
||||
public ManiaAction NormalActionStart;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ManiaAction"/> for the special column.
|
||||
/// </summary>
|
||||
public ManiaAction SpecialAction;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a list of <see cref="KeyBinding"/>s for a specific number of columns.
|
||||
/// </summary>
|
||||
/// <param name="columns">The number of columns that need to be bound.</param>
|
||||
/// <param name="nextNormalAction">The next <see cref="ManiaAction"/> to use for normal columns.</param>
|
||||
/// <returns>The keybindings.</returns>
|
||||
public IEnumerable<KeyBinding> GenerateKeyBindingsFor(int columns, out ManiaAction nextNormalAction)
|
||||
{
|
||||
ManiaAction currentNormalAction = NormalActionStart;
|
||||
|
||||
var bindings = new List<KeyBinding>();
|
||||
|
||||
for (int i = LeftKeys.Length - columns / 2; i < LeftKeys.Length; i++)
|
||||
bindings.Add(new KeyBinding(LeftKeys[i], currentNormalAction++));
|
||||
|
||||
for (int i = 0; i < columns / 2; i++)
|
||||
bindings.Add(new KeyBinding(RightKeys[i], currentNormalAction++));
|
||||
|
||||
if (columns % 2 == 1)
|
||||
bindings.Add(new KeyBinding(SpecialKey, SpecialAction));
|
||||
|
||||
nextNormalAction = currentNormalAction;
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum PlayfieldType
|
||||
{
|
||||
/// <summary>
|
||||
/// Columns are grouped into a single stage.
|
||||
/// Number of columns in this stage lies at (item - Single).
|
||||
/// </summary>
|
||||
Single = 0,
|
||||
/// <summary>
|
||||
/// Columns are grouped into two stages.
|
||||
/// Overall number of columns lies at (item - Dual), further computation is required for
|
||||
/// number of columns in each individual stage.
|
||||
/// </summary>
|
||||
Dual = 1000,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
/// </summary>
|
||||
internal class FastRandom
|
||||
{
|
||||
private const double uint_to_real = 1.0 / (uint.MaxValue + 1.0);
|
||||
private const double int_to_real = 1.0 / (int.MaxValue + 1.0);
|
||||
private const uint int_mask = 0x7FFFFFFF;
|
||||
private const uint y = 842502087;
|
||||
private const uint z = 3579807591;
|
||||
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
/// Generates a random double value within the range [0, 1).
|
||||
/// </summary>
|
||||
/// <returns>The random value.</returns>
|
||||
public double NextDouble() => uint_to_real * NextUInt();
|
||||
public double NextDouble() => int_to_real * Next();
|
||||
|
||||
private uint bitBuffer;
|
||||
private int bitIndex = 32;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public interface IPlayfieldTypeMod : IApplicableMod
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="PlayfieldType"/> which this <see cref="IPlayfieldTypeMod"/> requires.
|
||||
/// </summary>
|
||||
PlayfieldType PlayfieldType { get; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
return new Score
|
||||
{
|
||||
User = new User { Username = "osu!topus!" },
|
||||
Replay = new ManiaAutoGenerator(beatmap).Generate(),
|
||||
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter<ManiaHitObject>, IApplicableToRulesetContainer<ManiaHitObject>
|
||||
{
|
||||
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 => 0;
|
||||
|
||||
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
|
||||
{
|
||||
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
||||
|
||||
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||
if (mbc.IsForCurrentRuleset)
|
||||
return;
|
||||
|
||||
mbc.TargetColumns *= 2;
|
||||
}
|
||||
|
||||
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||
{
|
||||
var mrc = (ManiaRulesetContainer)rulesetContainer;
|
||||
|
||||
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||
if (mrc.IsForCurrentRuleset)
|
||||
return;
|
||||
|
||||
var newDefinitions = new List<StageDefinition>();
|
||||
foreach (var existing in mrc.Beatmap.Stages)
|
||||
{
|
||||
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
||||
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
||||
}
|
||||
|
||||
mrc.Beatmap.Stages = newDefinitions;
|
||||
}
|
||||
|
||||
public PlayfieldType PlayfieldType => PlayfieldType.Dual;
|
||||
}
|
||||
}
|
||||
@@ -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!";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) };
|
||||
|
||||
@@ -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) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +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.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModKeyCoop : Mod
|
||||
{
|
||||
public override string Name => "KeyCoop";
|
||||
public override string ShortenedName => "2P";
|
||||
public override string Description => @"Double the key amount, double the fun!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModMirror : Mod, IApplicableToRulesetContainer<ManiaHitObject>
|
||||
{
|
||||
public override string Name => "Mirror";
|
||||
public override string ShortenedName => "MR";
|
||||
public override ModType Type => ModType.Special;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
|
||||
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||
{
|
||||
var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
|
||||
|
||||
rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = availableColumns - 1 - h.Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 1;
|
||||
|
||||
Add(new Box
|
||||
AddInternal(new Box
|
||||
{
|
||||
Name = "Bar line",
|
||||
Anchor = Anchor.BottomCentre,
|
||||
@@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
if (isMajor)
|
||||
{
|
||||
Add(new EquilateralTriangle
|
||||
AddInternal(new EquilateralTriangle
|
||||
{
|
||||
Name = "Left triangle",
|
||||
Anchor = Anchor.BottomLeft,
|
||||
@@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
Rotation = 90
|
||||
});
|
||||
|
||||
Add(new EquilateralTriangle
|
||||
AddInternal(new EquilateralTriangle
|
||||
{
|
||||
Name = "Right triangle",
|
||||
Anchor = Anchor.BottomRight,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// 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.Linq;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Graphics;
|
||||
@@ -43,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
// The hit object itself cannot be used for various elements because the tail overshoots it
|
||||
// So a specialized container that is updated to contain the tail height is used
|
||||
@@ -69,7 +68,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
foreach (var tick in HitObject.NestedHitObjects.OfType<HoldNoteTick>())
|
||||
{
|
||||
@@ -212,7 +211,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (timeOffset > HitObject.HitWindows.Bad / 2)
|
||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||
{
|
||||
AddJudgement(new HoldNoteTailJudgement
|
||||
{
|
||||
@@ -224,14 +223,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
return;
|
||||
}
|
||||
|
||||
double offset = Math.Abs(timeOffset);
|
||||
|
||||
if (offset > HitObject.HitWindows.Miss / 2)
|
||||
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
||||
if (result == HitResult.None)
|
||||
return;
|
||||
|
||||
AddJudgement(new HoldNoteTailJudgement
|
||||
{
|
||||
Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss,
|
||||
Result = result,
|
||||
HasBroken = holdNote.hasBroken
|
||||
});
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Size = new Vector2(1);
|
||||
|
||||
Children = new[]
|
||||
InternalChildren = new[]
|
||||
{
|
||||
glowContainer = new CircularContainer
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// 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 OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Bindings;
|
||||
@@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Children = new Drawable[]
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
laneGlowPiece = new LaneGlowPiece
|
||||
{
|
||||
@@ -63,17 +62,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (timeOffset > HitObject.HitWindows.Bad / 2)
|
||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||
AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
|
||||
return;
|
||||
}
|
||||
|
||||
double offset = Math.Abs(timeOffset);
|
||||
|
||||
if (offset > HitObject.HitWindows.Miss / 2)
|
||||
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
||||
if (result == HitResult.None)
|
||||
return;
|
||||
|
||||
AddJudgement(new ManiaJudgement { Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss });
|
||||
AddJudgement(new ManiaJudgement { Result = result });
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Mania.Objects.Types;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
@@ -9,5 +11,13 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
public abstract class ManiaHitObject : HitObject, IHasColumn
|
||||
{
|
||||
public virtual int Column { get; set; }
|
||||
|
||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
HitWindows.AllowsPerfect = true;
|
||||
HitWindows.AllowsOk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
// 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 System;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
{
|
||||
internal class ManiaHitObjectDifficulty
|
||||
{
|
||||
/// <summary>
|
||||
/// Factor by how much individual / overall strain decays per second.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These values are results of tweaking a lot and taking into account general feedback.
|
||||
/// </remarks>
|
||||
internal const double INDIVIDUAL_DECAY_BASE = 0.125;
|
||||
internal const double OVERALL_DECAY_BASE = 0.30;
|
||||
|
||||
internal ManiaHitObject BaseHitObject;
|
||||
|
||||
private readonly int beatmapColumnCount;
|
||||
|
||||
|
||||
private readonly double endTime;
|
||||
private readonly double[] heldUntil;
|
||||
|
||||
/// <summary>
|
||||
/// Measures jacks or more generally: repeated presses of the same button
|
||||
/// </summary>
|
||||
private readonly double[] individualStrains;
|
||||
|
||||
internal double IndividualStrain
|
||||
{
|
||||
get
|
||||
{
|
||||
return individualStrains[BaseHitObject.Column];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
individualStrains[BaseHitObject.Column] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Measures note density in a way
|
||||
/// </summary>
|
||||
internal double OverallStrain = 1;
|
||||
|
||||
public ManiaHitObjectDifficulty(ManiaHitObject baseHitObject, int columnCount)
|
||||
{
|
||||
BaseHitObject = baseHitObject;
|
||||
|
||||
endTime = (baseHitObject as IHasEndTime)?.EndTime ?? baseHitObject.StartTime;
|
||||
|
||||
beatmapColumnCount = columnCount;
|
||||
heldUntil = new double[beatmapColumnCount];
|
||||
individualStrains = new double[beatmapColumnCount];
|
||||
|
||||
for (int i = 0; i < beatmapColumnCount; ++i)
|
||||
{
|
||||
individualStrains[i] = 0;
|
||||
heldUntil[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal void CalculateStrains(ManiaHitObjectDifficulty previousHitObject, double timeRate)
|
||||
{
|
||||
// TODO: Factor in holds
|
||||
double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate;
|
||||
double individualDecay = Math.Pow(INDIVIDUAL_DECAY_BASE, timeElapsed / 1000);
|
||||
double overallDecay = Math.Pow(OVERALL_DECAY_BASE, timeElapsed / 1000);
|
||||
|
||||
double holdFactor = 1.0; // Factor to all additional strains in case something else is held
|
||||
double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly
|
||||
|
||||
// Fill up the heldUntil array
|
||||
for (int i = 0; i < beatmapColumnCount; ++i)
|
||||
{
|
||||
heldUntil[i] = previousHitObject.heldUntil[i];
|
||||
|
||||
// If there is at least one other overlapping end or note, then we get an addition, buuuuuut...
|
||||
if (BaseHitObject.StartTime < heldUntil[i] && endTime > heldUntil[i])
|
||||
{
|
||||
holdAddition = 1.0;
|
||||
}
|
||||
|
||||
// ... this addition only is valid if there is _no_ other note with the same ending. Releasing multiple notes at the same time is just as easy as releasing 1
|
||||
if (endTime == heldUntil[i])
|
||||
{
|
||||
holdAddition = 0;
|
||||
}
|
||||
|
||||
// We give a slight bonus to everything if something is held meanwhile
|
||||
if (heldUntil[i] > endTime)
|
||||
{
|
||||
holdFactor = 1.25;
|
||||
}
|
||||
|
||||
// Decay individual strains
|
||||
individualStrains[i] = previousHitObject.individualStrains[i] * individualDecay;
|
||||
}
|
||||
|
||||
heldUntil[BaseHitObject.Column] = endTime;
|
||||
|
||||
// Increase individual strain in own column
|
||||
IndividualStrain += 2.0 * holdFactor;
|
||||
|
||||
OverallStrain = previousHitObject.OverallStrain * overallDecay + (1.0 + holdAddition) * holdFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
{
|
||||
/// <summary>
|
||||
@@ -13,17 +8,5 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
/// </summary>
|
||||
public class Note : ManiaHitObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The key-press hit window for this note.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public HitWindows HitWindows { get; protected set; } = new HitWindows();
|
||||
|
||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
HitWindows = new HitWindows(difficulty.OverallDifficulty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
@@ -15,10 +15,31 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
{
|
||||
public const double RELEASE_DELAY = 20;
|
||||
|
||||
public ManiaAutoGenerator(Beatmap<ManiaHitObject> beatmap)
|
||||
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
|
||||
|
||||
private readonly ManiaAction[] columnActions;
|
||||
|
||||
public ManiaAutoGenerator(ManiaBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
Replay = new Replay { User = new User { Username = @"Autoplay" } };
|
||||
|
||||
columnActions = new ManiaAction[Beatmap.TotalColumns];
|
||||
|
||||
var normalAction = ManiaAction.Key1;
|
||||
var specialAction = ManiaAction.Special1;
|
||||
int totalCounter = 0;
|
||||
foreach (var stage in Beatmap.Stages)
|
||||
{
|
||||
for (int i = 0; i < stage.Columns; i++)
|
||||
{
|
||||
if (stage.IsSpecialColumn(i))
|
||||
columnActions[totalCounter] = specialAction++;
|
||||
else
|
||||
columnActions[totalCounter] = normalAction++;
|
||||
totalCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Replay Replay;
|
||||
@@ -30,18 +51,18 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
|
||||
var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time);
|
||||
|
||||
int activeColumns = 0;
|
||||
var actions = new List<ManiaAction>();
|
||||
foreach (var group in pointGroups)
|
||||
{
|
||||
foreach (var point in group)
|
||||
{
|
||||
if (point is HitPoint)
|
||||
activeColumns |= 1 << point.Column;
|
||||
actions.Add(columnActions[point.Column]);
|
||||
if (point is ReleasePoint)
|
||||
activeColumns ^= 1 << point.Column;
|
||||
actions.Remove(columnActions[point.Column]);
|
||||
}
|
||||
|
||||
Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, activeColumns));
|
||||
Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray()));
|
||||
}
|
||||
|
||||
return Replay;
|
||||
|
||||
@@ -4,40 +4,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Replays
|
||||
{
|
||||
internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler
|
||||
internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler<ManiaReplayFrame>
|
||||
{
|
||||
private readonly ManiaRulesetContainer container;
|
||||
|
||||
public ManiaFramedReplayInputHandler(Replay replay, ManiaRulesetContainer container)
|
||||
public ManiaFramedReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
private ManiaPlayfield playfield;
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
var actions = new List<ManiaAction>();
|
||||
protected override bool IsImportant(ManiaReplayFrame frame) => frame.Actions.Any();
|
||||
|
||||
if (playfield == null)
|
||||
playfield = (ManiaPlayfield)container.Playfield;
|
||||
|
||||
int activeColumns = (int)(CurrentFrame.MouseX ?? 0);
|
||||
int counter = 0;
|
||||
while (activeColumns > 0)
|
||||
{
|
||||
if ((activeColumns & 1) > 0)
|
||||
actions.Add(playfield.Columns.ElementAt(counter).Action);
|
||||
counter++;
|
||||
activeColumns >>= 1;
|
||||
}
|
||||
|
||||
return new List<InputState> { new ReplayState<ManiaAction> { PressedActions = actions } };
|
||||
}
|
||||
public override List<InputState> GetPendingStates() => new List<InputState> { new ReplayState<ManiaAction> { PressedActions = CurrentFrame.Actions } };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,59 @@
|
||||
// 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.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Replays.Legacy;
|
||||
using osu.Game.Rulesets.Replays.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Replays
|
||||
{
|
||||
public class ManiaReplayFrame : ReplayFrame
|
||||
public class ManiaReplayFrame : ReplayFrame, IConvertibleReplayFrame
|
||||
{
|
||||
public override bool IsImportant => MouseX > 0;
|
||||
public List<ManiaAction> Actions = new List<ManiaAction>();
|
||||
|
||||
public ManiaReplayFrame(double time, int activeColumns)
|
||||
: base(time, activeColumns, null, ReplayButtonState.None)
|
||||
public ManiaReplayFrame()
|
||||
{
|
||||
}
|
||||
|
||||
public ManiaReplayFrame(double time, params ManiaAction[] actions)
|
||||
: base(time)
|
||||
{
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
|
||||
{
|
||||
// We don't need to fully convert, just create the converter
|
||||
var converter = new ManiaBeatmapConverter(beatmap.BeatmapInfo.RulesetID == 3, beatmap);
|
||||
|
||||
// NB: Via co-op mod, osu-stable can have two stages with floor(col/2) and ceil(col/2) columns. This will need special handling
|
||||
// elsewhere in the game if we do choose to support the old co-op mod anyway. For now, assume that there is only one stage.
|
||||
|
||||
var stage = new StageDefinition { Columns = converter.TargetColumns };
|
||||
|
||||
var normalAction = ManiaAction.Key1;
|
||||
var specialAction = ManiaAction.Special1;
|
||||
|
||||
int activeColumns = (int)(legacyFrame.MouseX ?? 0);
|
||||
int counter = 0;
|
||||
while (activeColumns > 0)
|
||||
{
|
||||
var isSpecial = stage.IsSpecialColumn(counter);
|
||||
|
||||
if ((activeColumns & 1) > 0)
|
||||
Actions.Add(isSpecial ? specialAction : normalAction);
|
||||
|
||||
if (isSpecial)
|
||||
specialAction++;
|
||||
else
|
||||
normalAction++;
|
||||
|
||||
counter++;
|
||||
activeColumns >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"Mappings": [{
|
||||
"StartTime": 500,
|
||||
"Objects": [{
|
||||
"StartTime": 500,
|
||||
"EndTime": 2500,
|
||||
"Column": 0
|
||||
},
|
||||
{
|
||||
"StartTime": 1500,
|
||||
"EndTime": 2500,
|
||||
"Column": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"StartTime": 3000,
|
||||
"Objects": [{
|
||||
"StartTime": 3000,
|
||||
"EndTime": 4000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 4500,
|
||||
"Objects": [{
|
||||
"StartTime": 4500,
|
||||
"EndTime": 5500,
|
||||
"Column": 4
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 6000,
|
||||
"Objects": [{
|
||||
"StartTime": 6000,
|
||||
"EndTime": 6500,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 7000,
|
||||
"Objects": [{
|
||||
"StartTime": 7000,
|
||||
"EndTime": 8000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 8500,
|
||||
"Objects": [{
|
||||
"StartTime": 8500,
|
||||
"EndTime": 11000,
|
||||
"Column": 0
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 11500,
|
||||
"Objects": [{
|
||||
"StartTime": 11500,
|
||||
"EndTime": 12000,
|
||||
"Column": 1
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 12500,
|
||||
"Objects": [{
|
||||
"StartTime": 12500,
|
||||
"EndTime": 16500,
|
||||
"Column": 4
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 17000,
|
||||
"Objects": [{
|
||||
"StartTime": 17000,
|
||||
"EndTime": 18000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 18500,
|
||||
"Objects": [{
|
||||
"StartTime": 18500,
|
||||
"EndTime": 19450,
|
||||
"Column": 0
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 19875,
|
||||
"Objects": [{
|
||||
"StartTime": 19875,
|
||||
"EndTime": 23875,
|
||||
"Column": 1
|
||||
},
|
||||
{
|
||||
"StartTime": 19875,
|
||||
"EndTime": 23875,
|
||||
"Column": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
osu file format v14
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:6
|
||||
CircleSize:4
|
||||
OverallDifficulty:7
|
||||
ApproachRate:8.3
|
||||
SliderMultiplier:1.6
|
||||
SliderTickRate:1
|
||||
|
||||
[TimingPoints]
|
||||
500,500,4,2,1,50,1,0
|
||||
13426,-100,4,3,1,45,0,0
|
||||
14884,-100,4,2,1,50,0,0
|
||||
|
||||
[HitObjects]
|
||||
96,192,500,6,0,L|416:192,2,320
|
||||
256,192,3000,12,0,4000,0:0:0:0:
|
||||
256,192,4500,12,0,5500,0:0:0:0:
|
||||
256,192,6000,12,0,6500,0:0:0:0:
|
||||
256,128,7000,6,0,L|352:128,4,80
|
||||
32,192,8500,6,0,B|32:384|256:384|256:192|256:192|256:0|512:0|512:192,1,800
|
||||
256,192,11500,12,0,12000,0:0:0:0:
|
||||
512,320,12500,6,0,B|0:256|0:256|512:96|512:96|256:32,1,1280
|
||||
256,256,17000,6,0,L|160:256,4,80
|
||||
256,192,18500,12,0,19450,0:0:0:0:
|
||||
216,231,19875,6,0,B|216:135|280:135|344:135|344:199|344:263|248:327|248:327|120:327|120:327|56:39|408:39|408:39|472:150|408:342,1,1280
|
||||
@@ -0,0 +1,60 @@
|
||||
// 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.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||
|
||||
private bool isForCurrentRuleset;
|
||||
|
||||
[NonParallelizable]
|
||||
[TestCase("basic", false)]
|
||||
public void Test(string name, bool isForCurrentRuleset)
|
||||
{
|
||||
this.isForCurrentRuleset = isForCurrentRuleset;
|
||||
base.Test(name);
|
||||
}
|
||||
|
||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||
{
|
||||
yield return new ConvertValue
|
||||
{
|
||||
StartTime = hitObject.StartTime,
|
||||
EndTime = (hitObject as IHasEndTime)?.EndTime ?? hitObject.StartTime,
|
||||
Column = ((ManiaHitObject)hitObject).Column
|
||||
};
|
||||
}
|
||||
|
||||
protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new ManiaBeatmapConverter(isForCurrentRuleset, beatmap);
|
||||
}
|
||||
|
||||
public struct ConvertValue : IEquatable<ConvertValue>
|
||||
{
|
||||
/// <summary>
|
||||
/// A sane value to account for osu!stable using ints everwhere.
|
||||
/// </summary>
|
||||
private const float conversion_lenience = 2;
|
||||
|
||||
public double StartTime;
|
||||
public double EndTime;
|
||||
public int Column;
|
||||
|
||||
public bool Equals(ConvertValue other)
|
||||
=> Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience)
|
||||
&& Precision.AlmostEquals(EndTime, other.EndTime, conversion_lenience)
|
||||
&& Column == other.Column;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
[TestFixture]
|
||||
public class TestCaseAutoGeneration : OsuTestCase
|
||||
{
|
||||
[Test]
|
||||
@@ -19,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | - |
|
||||
// | |
|
||||
|
||||
var beatmap = new Beatmap<ManiaHitObject>();
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 });
|
||||
beatmap.HitObjects.Add(new Note { StartTime = 1000 });
|
||||
|
||||
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||
@@ -27,8 +29,8 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||
Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 0 has not been pressed");
|
||||
Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 0 has not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Special1), "Special1 has not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Special1), "Special1 has not been released");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -40,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | * |
|
||||
// | |
|
||||
|
||||
var beatmap = new Beatmap<ManiaHitObject>();
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
|
||||
|
||||
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||
@@ -48,8 +50,8 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 0 has not been pressed");
|
||||
Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 0 has not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Special1), "Special1 has not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Special1), "Special1 has not been released");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -59,7 +61,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | - | - |
|
||||
// | | |
|
||||
|
||||
var beatmap = new Beatmap<ManiaHitObject>();
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 });
|
||||
beatmap.HitObjects.Add(new Note { StartTime = 1000 });
|
||||
beatmap.HitObjects.Add(new Note { StartTime = 1000, Column = 1 });
|
||||
|
||||
@@ -68,8 +70,8 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||
Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||
Assert.AreEqual(3, generated.Frames[1].MouseX, "Keys 1 and 2 have not been pressed");
|
||||
Assert.AreEqual(0, generated.Frames[2].MouseX, "Keys 1 and 2 have not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -81,7 +83,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | * | * |
|
||||
// | | |
|
||||
|
||||
var beatmap = new Beatmap<ManiaHitObject>();
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000, Column = 1 });
|
||||
|
||||
@@ -90,8 +92,8 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||
Assert.AreEqual(3, generated.Frames[1].MouseX, "Keys 1 and 2 have not been pressed");
|
||||
Assert.AreEqual(0, generated.Frames[2].MouseX, "Keys 1 and 2 have not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -102,7 +104,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | - | |
|
||||
// | | |
|
||||
|
||||
var beatmap = new Beatmap<ManiaHitObject>();
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 });
|
||||
beatmap.HitObjects.Add(new Note { StartTime = 1000 });
|
||||
beatmap.HitObjects.Add(new Note { StartTime = 2000, Column = 1 });
|
||||
|
||||
@@ -113,10 +115,10 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect first note release time");
|
||||
Assert.AreEqual(2000, generated.Frames[3].Time, "Incorrect second note hit time");
|
||||
Assert.AreEqual(2000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time");
|
||||
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed");
|
||||
Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 1 has not been released");
|
||||
Assert.AreEqual(2, generated.Frames[3].MouseX, "Key 2 has not been pressed");
|
||||
Assert.AreEqual(0, generated.Frames[4].MouseX, "Key 2 has not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1), "Key1 has not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1), "Key1 has not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[3], ManiaAction.Key2), "Key2 has not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[4], ManiaAction.Key2), "Key2 has not been released");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -129,7 +131,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | * | |
|
||||
// | | |
|
||||
|
||||
var beatmap = new Beatmap<ManiaHitObject>();
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 2000, Duration = 2000, Column = 1 });
|
||||
|
||||
@@ -140,10 +142,11 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect first note release time");
|
||||
Assert.AreEqual(2000, generated.Frames[2].Time, "Incorrect second note hit time");
|
||||
Assert.AreEqual(4000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time");
|
||||
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed");
|
||||
Assert.AreEqual(3, generated.Frames[2].MouseX, "Keys 1 and 2 have not been pressed");
|
||||
Assert.AreEqual(2, generated.Frames[3].MouseX, "Key 1 has not been released");
|
||||
Assert.AreEqual(0, generated.Frames[4].MouseX, "Key 2 has not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1), "Key1 has not been pressed");
|
||||
Assert.IsTrue(checkContains(generated.Frames[2], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[3], ManiaAction.Key1), "Key1 has not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[3], ManiaAction.Key2), "Key2 has been released");
|
||||
Assert.IsFalse(checkContains(generated.Frames[4], ManiaAction.Key2), "Key2 has not been released");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -155,7 +158,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | * | |
|
||||
// | | |
|
||||
|
||||
var beatmap = new Beatmap<ManiaHitObject>();
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 - ManiaAutoGenerator.RELEASE_DELAY });
|
||||
beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 });
|
||||
|
||||
@@ -165,9 +168,12 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time");
|
||||
Assert.AreEqual(3000, generated.Frames[2].Time, "Incorrect second note press time + first note release time");
|
||||
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect second note release time");
|
||||
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed");
|
||||
Assert.AreEqual(2, generated.Frames[2].MouseX, "Key 1 has not been released or key 2 has not been pressed");
|
||||
Assert.AreEqual(0, generated.Frames[3].MouseX, "Keys 1 and 2 have not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1), "Key1 has not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1), "Key1 has not been released");
|
||||
Assert.IsTrue(checkContains(generated.Frames[2], ManiaAction.Key2), "Key2 has not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[3], ManiaAction.Key2), "Key2 has not been released");
|
||||
}
|
||||
|
||||
private bool checkContains(ReplayFrame frame, params ManiaAction[] actions) => actions.All(action => ((ManiaReplayFrame)frame).Actions.Contains(action));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ using OpenTK.Graphics;
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseManiaHitObjects : OsuTestCase
|
||||
{
|
||||
public TestCaseManiaHitObjects()
|
||||
@@ -78,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
RelativeChildSize = new Vector2(1, 10000),
|
||||
Children = new[]
|
||||
{
|
||||
new DrawableHoldNote(new HoldNote { Duration = 1 }, ManiaAction.Key1)
|
||||
new DrawableHoldNote(new HoldNote { Duration = 1000 } , ManiaAction.Key1)
|
||||
{
|
||||
Y = 5000,
|
||||
Height = 1000,
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
@@ -17,7 +21,6 @@ using osu.Game.Tests.Visual;
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseManiaPlayfield : OsuTestCase
|
||||
{
|
||||
private const double start_time = 500;
|
||||
@@ -31,15 +34,43 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
var rng = new Random(1337);
|
||||
|
||||
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
||||
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
||||
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
||||
AddStep("Right special style", () => createPlayfield(4, SpecialColumnPosition.Right));
|
||||
AddStep("5 columns", () => createPlayfield(5, SpecialColumnPosition.Normal));
|
||||
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal));
|
||||
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
|
||||
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
|
||||
AddStep("Reversed", () => createPlayfield(4, SpecialColumnPosition.Normal, true));
|
||||
AddStep("1 column", () => createPlayfield(1));
|
||||
AddStep("4 columns", () => createPlayfield(4));
|
||||
AddStep("5 columns", () => createPlayfield(5));
|
||||
AddStep("8 columns", () => createPlayfield(8));
|
||||
AddStep("4 + 4 columns", () =>
|
||||
{
|
||||
var stages = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = 4 },
|
||||
new StageDefinition { Columns = 4 },
|
||||
};
|
||||
createPlayfield(stages);
|
||||
});
|
||||
|
||||
AddStep("2 + 4 + 2 columns", () =>
|
||||
{
|
||||
var stages = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = 2 },
|
||||
new StageDefinition { Columns = 4 },
|
||||
new StageDefinition { Columns = 2 },
|
||||
};
|
||||
createPlayfield(stages);
|
||||
});
|
||||
|
||||
AddStep("1 + 8 + 1 columns", () =>
|
||||
{
|
||||
var stages = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = 1 },
|
||||
new StageDefinition { Columns = 8 },
|
||||
new StageDefinition { Columns = 1 },
|
||||
};
|
||||
createPlayfield(stages);
|
||||
});
|
||||
|
||||
AddStep("Reversed", () => createPlayfield(4, true));
|
||||
|
||||
AddStep("Notes with input", () => createPlayfieldWithNotes());
|
||||
AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(true));
|
||||
@@ -48,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
|
||||
AddStep("Hit explosion", () =>
|
||||
{
|
||||
var playfield = createPlayfield(4, SpecialColumnPosition.Normal);
|
||||
var playfield = createPlayfield(4);
|
||||
|
||||
int col = rng.Next(0, 4);
|
||||
|
||||
@@ -58,28 +89,46 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
};
|
||||
|
||||
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
||||
playfield.Columns[col].OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
||||
});
|
||||
}
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
private void load(RulesetStore rulesets, SettingsStore settings)
|
||||
{
|
||||
maniaRuleset = rulesets.GetRuleset(3);
|
||||
|
||||
dependencies.Cache(new ManiaConfigManager(settings, maniaRuleset, 4));
|
||||
}
|
||||
|
||||
private ManiaPlayfield createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false)
|
||||
private ManiaPlayfield createPlayfield(int cols, bool inverted = false)
|
||||
{
|
||||
var stages = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = cols },
|
||||
};
|
||||
|
||||
return createPlayfield(stages, inverted);
|
||||
}
|
||||
|
||||
private ManiaPlayfield createPlayfield(List<StageDefinition> stages, bool inverted = false)
|
||||
{
|
||||
Clear();
|
||||
|
||||
var inputManager = new ManiaInputManager(maniaRuleset, cols) { RelativeSizeAxes = Axes.Both };
|
||||
var inputManager = new ManiaInputManager(maniaRuleset, stages.Sum(g => g.Columns)) { RelativeSizeAxes = Axes.Both };
|
||||
Add(inputManager);
|
||||
|
||||
ManiaPlayfield playfield;
|
||||
inputManager.Add(playfield = new ManiaPlayfield(cols)
|
||||
|
||||
inputManager.Add(playfield = new ManiaPlayfield(stages)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
SpecialColumnPosition = specialPos
|
||||
});
|
||||
|
||||
playfield.Inverted.Value = inverted;
|
||||
@@ -97,7 +146,12 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Add(inputManager);
|
||||
|
||||
ManiaPlayfield playfield;
|
||||
inputManager.Add(playfield = new ManiaPlayfield(4)
|
||||
var stages = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = 4 },
|
||||
};
|
||||
|
||||
inputManager.Add(playfield = new ManiaPlayfield(stages)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
||||
@@ -5,7 +5,7 @@ using NUnit.Framework;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
[TestFixture]
|
||||
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
|
||||
{
|
||||
public TestCasePerformancePoints()
|
||||
|
||||
@@ -11,13 +11,14 @@ using osu.Framework.Graphics.Colour;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class Column : ScrollingPlayfield, IHasAccentColour
|
||||
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||
{
|
||||
private const float key_icon_size = 10;
|
||||
private const float key_icon_corner_radius = 3;
|
||||
@@ -47,6 +48,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
public Column()
|
||||
: base(ScrollingDirection.Up)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = column_width;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
@@ -61,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
Name = "Hit target + hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION },
|
||||
Padding = new MarginPadding { Top = ManiaStage.HIT_TARGET_POSITION },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
@@ -115,7 +117,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
Name = "Key",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = ManiaPlayfield.HIT_TARGET_POSITION,
|
||||
Height = ManiaStage.HIT_TARGET_POSITION,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
@@ -205,12 +207,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
hitObject.Depth = (float)hitObject.HitObject.StartTime;
|
||||
hitObject.AccentColour = AccentColour;
|
||||
hitObject.OnJudgement += onJudgement;
|
||||
hitObject.OnJudgement += OnJudgement;
|
||||
|
||||
HitObjects.Add(hitObject);
|
||||
}
|
||||
|
||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (!judgement.IsHit)
|
||||
return;
|
||||
@@ -258,5 +260,26 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
public bool OnPressed(ManiaAction action) => Pressed?.Invoke(action) ?? false;
|
||||
public bool OnReleased(ManiaAction action) => Released?.Invoke(action) ?? false;
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
// Play the sounds of the next hitobject
|
||||
if (HitObjects.AliveObjects.Any())
|
||||
{
|
||||
// If there are alive hitobjects, we can abuse the fact that AliveObjects are sorted by time (see: Add())
|
||||
HitObjects.AliveObjects.First().PlaySamples();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not, we do a slow search - we might want to do a BinarySearch here if this becomes problematic
|
||||
// We fallback to LastOrDefault() if we're beyond the last note in the map
|
||||
var hitObject = HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.LastOrDefault();
|
||||
hitObject?.PlaySamples();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnReleased(ManiaAction action) => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
internal class DrawableManiaJudgement : DrawableJudgement
|
||||
{
|
||||
public DrawableManiaJudgement(Judgement judgement)
|
||||
: base(judgement)
|
||||
public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject)
|
||||
: base(judgement, judgedObject)
|
||||
{
|
||||
JudgementText.TextSize = 25;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
if (JudgementText != null)
|
||||
JudgementText.TextSize = 25;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
||||
@@ -3,237 +3,92 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaPlayfield : ScrollingPlayfield
|
||||
{
|
||||
public const float HIT_TARGET_POSITION = 50;
|
||||
|
||||
private SpecialColumnPosition specialColumnPosition;
|
||||
/// <summary>
|
||||
/// The style to use for the special column.
|
||||
/// </summary>
|
||||
public SpecialColumnPosition SpecialColumnPosition
|
||||
{
|
||||
get { return specialColumnPosition; }
|
||||
set
|
||||
{
|
||||
if (IsLoaded)
|
||||
throw new InvalidOperationException($"Setting {nameof(SpecialColumnPosition)} after the playfield is loaded requires re-creating the playfield.");
|
||||
specialColumnPosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this playfield should be inverted. This flips everything inside the playfield.
|
||||
/// </summary>
|
||||
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
|
||||
|
||||
private readonly FlowContainer<Column> columns;
|
||||
public IEnumerable<Column> Columns => columns.Children;
|
||||
public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
|
||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container<Drawable> content;
|
||||
|
||||
private List<Color4> normalColumnColours = new List<Color4>();
|
||||
private Color4 specialColumnColour;
|
||||
|
||||
private readonly Container<DrawableManiaJudgement> judgements;
|
||||
|
||||
private readonly int columnCount;
|
||||
|
||||
public ManiaPlayfield(int columnCount)
|
||||
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
||||
: base(ScrollingDirection.Up)
|
||||
{
|
||||
this.columnCount = columnCount;
|
||||
if (stageDefinitions == null)
|
||||
throw new ArgumentNullException(nameof(stageDefinitions));
|
||||
|
||||
if (columnCount <= 0)
|
||||
throw new ArgumentException("Can't have zero or fewer columns.");
|
||||
if (stageDefinitions.Count <= 0)
|
||||
throw new ArgumentException("Can't have zero or fewer stages.");
|
||||
|
||||
Inverted.Value = true;
|
||||
|
||||
Container topLevelContainer;
|
||||
InternalChildren = new Drawable[]
|
||||
GridContainer playfieldGrid;
|
||||
InternalChild = playfieldGrid = new GridContainer
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Name = "Playfield elements",
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Name = "Columns mask",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Name = "Background",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black
|
||||
},
|
||||
columns = new FillFlowContainer<Column>
|
||||
{
|
||||
Name = "Columns",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Padding = new MarginPadding { Left = 1, Right = 1 },
|
||||
Spacing = new Vector2(1, 0)
|
||||
},
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Barlines mask",
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 1366, // Bar lines should only be masked on the vertical axis
|
||||
BypassAutoSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Child = content = new Container
|
||||
{
|
||||
Name = "Bar lines",
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
|
||||
}
|
||||
},
|
||||
judgements = new Container<DrawableManiaJudgement>
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Y = HIT_TARGET_POSITION + 150,
|
||||
BypassAutoSizeAxes = Axes.Both
|
||||
},
|
||||
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
}
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[] { new Drawable[stageDefinitions.Count] }
|
||||
};
|
||||
|
||||
var currentAction = ManiaAction.Key1;
|
||||
for (int i = 0; i < columnCount; i++)
|
||||
var normalColumnAction = ManiaAction.Key1;
|
||||
var specialColumnAction = ManiaAction.Special1;
|
||||
int firstColumnIndex = 0;
|
||||
for (int i = 0; i < stageDefinitions.Count; i++)
|
||||
{
|
||||
var c = new Column();
|
||||
c.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||
newStage.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||
newStage.Inverted.BindTo(Inverted);
|
||||
|
||||
c.IsSpecial = isSpecialColumn(i);
|
||||
c.Action = c.IsSpecial ? ManiaAction.Special : currentAction++;
|
||||
playfieldGrid.Content[0][i] = newStage;
|
||||
|
||||
topLevelContainer.Add(c.TopLevelContainer.CreateProxy());
|
||||
stages.Add(newStage);
|
||||
AddNested(newStage);
|
||||
|
||||
columns.Add(c);
|
||||
AddNested(c);
|
||||
firstColumnIndex += newStage.Columns.Count;
|
||||
}
|
||||
|
||||
Inverted.ValueChanged += invertedChanged;
|
||||
Inverted.TriggerChange();
|
||||
}
|
||||
|
||||
private void invertedChanged(bool newValue)
|
||||
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
|
||||
|
||||
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
|
||||
|
||||
private ManiaStage getStageByColumn(int column)
|
||||
{
|
||||
Scale = new Vector2(1, newValue ? -1 : 1);
|
||||
judgements.Scale = Scale;
|
||||
int sum = 0;
|
||||
foreach (var stage in stages)
|
||||
{
|
||||
sum = sum + stage.Columns.Count;
|
||||
if (sum > column)
|
||||
return stage;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(ManiaConfigManager maniaConfig)
|
||||
{
|
||||
normalColumnColours = new List<Color4>
|
||||
{
|
||||
colours.RedDark,
|
||||
colours.GreenDark
|
||||
};
|
||||
|
||||
specialColumnColour = colours.BlueDark;
|
||||
|
||||
// Set the special column + colour + key
|
||||
foreach (var column in Columns)
|
||||
{
|
||||
if (!column.IsSpecial)
|
||||
continue;
|
||||
|
||||
column.AccentColour = specialColumnColour;
|
||||
}
|
||||
|
||||
var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList();
|
||||
|
||||
// We'll set the colours of the non-special columns in a separate loop, because the non-special
|
||||
// column colours are mirrored across their centre and special styles mess with this
|
||||
for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++)
|
||||
{
|
||||
Color4 colour = normalColumnColours[i % normalColumnColours.Count];
|
||||
nonSpecialColumns[i].AccentColour = colour;
|
||||
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
|
||||
}
|
||||
maniaConfig.BindWith(ManiaSetting.ScrollTime, VisibleTimeRange);
|
||||
}
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
judgements.Clear();
|
||||
judgements.Add(new DrawableManiaJudgement(judgement)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the column index is a special column for this playfield.
|
||||
/// </summary>
|
||||
/// <param name="column">The 0-based column index.</param>
|
||||
/// <returns>Whether the column is a special column.</returns>
|
||||
private bool isSpecialColumn(int column)
|
||||
{
|
||||
switch (SpecialColumnPosition)
|
||||
{
|
||||
default:
|
||||
case SpecialColumnPosition.Normal:
|
||||
return columnCount % 2 == 1 && column == columnCount / 2;
|
||||
case SpecialColumnPosition.Left:
|
||||
return column == 0;
|
||||
case SpecialColumnPosition.Right:
|
||||
return column == columnCount - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject h)
|
||||
{
|
||||
h.OnJudgement += OnJudgement;
|
||||
Columns.ElementAt(((ManiaHitObject)h.HitObject).Column).Add(h);
|
||||
}
|
||||
|
||||
public void Add(DrawableBarLine barline) => HitObjects.Add(barline);
|
||||
|
||||
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
|
||||
content.Width = columns.Width;
|
||||
getStageByColumn(((ManiaHitObject)judgedObject.HitObject).Column).OnJudgement(judgedObject, judgement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user