Skip to content

Commit

Permalink
Merge branch 'master' into remove-hold-note-ticks
Browse files Browse the repository at this point in the history
  • Loading branch information
bdach committed Oct 11, 2023
2 parents 041318e + eeb5409 commit 063623b
Show file tree
Hide file tree
Showing 46 changed files with 573 additions and 152 deletions.
51 changes: 51 additions & 0 deletions osu.Game.Rulesets.Catch/Difficulty/CatchLegacyScoreSimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
Expand Down Expand Up @@ -137,5 +140,53 @@ private void simulateHit(HitObject hitObject, ref LegacyScoreAttributes attribut
if (increaseCombo)
combo++;
}

public double GetLegacyScoreMultiplier(IReadOnlyList<Mod> mods, LegacyBeatmapConversionDifficultyInfo difficulty)
{
bool scoreV2 = mods.Any(m => m is ModScoreV2);

double multiplier = 1.0;

foreach (var mod in mods)
{
switch (mod)
{
case CatchModNoFail:
multiplier *= scoreV2 ? 1.0 : 0.5;
break;

case CatchModEasy:
multiplier *= 0.5;
break;

case CatchModHalfTime:
case CatchModDaycore:
multiplier *= 0.3;
break;

case CatchModHidden:
multiplier *= scoreV2 ? 1.0 : 1.06;
break;

case CatchModHardRock:
multiplier *= 1.12;
break;

case CatchModDoubleTime:
case CatchModNightcore:
multiplier *= 1.06;
break;

case CatchModFlashlight:
multiplier *= 1.12;
break;

case CatchModRelax:
return 0;
}
}

return multiplier;
}
}
}
6 changes: 5 additions & 1 deletion osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ public partial class ArgonCatcher : CompositeDrawable
[BackgroundDependencyLoader]
private void load()
{
RelativeSizeAxes = Axes.Both;
Anchor = Anchor.TopCentre;
Origin = Anchor.Centre;

RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;

InternalChildren = new Drawable[]
{
Expand Down
11 changes: 11 additions & 0 deletions osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Rulesets.Catch.UI;
using osuTK;

namespace osu.Game.Rulesets.Catch.Skinning.Default
{
Expand All @@ -22,6 +23,7 @@ public partial class DefaultCatcher : CompositeDrawable

public DefaultCatcher()
{
Anchor = Anchor.TopCentre;
RelativeSizeAxes = Axes.Both;
InternalChild = sprite = new Sprite
{
Expand All @@ -32,6 +34,15 @@ public DefaultCatcher()
};
}

protected override void Update()
{
base.Update();

// matches stable's origin position since we're using the same catcher sprite.
// see LegacyCatcher for more information.
OriginPosition = new Vector2(DrawWidth / 2, 16f);
}

[BackgroundDependencyLoader]
private void load(TextureStore store, Bindable<CatcherAnimationState> currentState)
{
Expand Down
33 changes: 33 additions & 0 deletions osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osuTK;

namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
public abstract partial class LegacyCatcher : CompositeDrawable
{
protected LegacyCatcher()
{
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;

// in stable, catcher sprites are displayed in their raw size. stable also has catcher sprites displayed with the following scale factors applied:
// 1. 0.5x, affecting all sprites in the playfield, computed here based on lazer's catch playfield dimensions (see WIDTH/HEIGHT constants in CatchPlayfield),
// source: https://github.com/peppy/osu-stable-reference/blob/1531237b63392e82c003c712faa028406073aa8f/osu!/GameplayElements/HitObjectManager.cs#L483-L494
// 2. 0.7x, a constant scale applied to all catcher sprites on construction.
AutoSizeAxes = Axes.Both;
Scale = new Vector2(0.5f * 0.7f);
}

protected override void Update()
{
base.Update();

// stable sets the Y origin position of the catcher to 16px in order for the catching range and OD scaling to align with the top of the catcher's plate in the default skin.
OriginPosition = new Vector2(DrawWidth / 2, 16f);
}
}
}
19 changes: 2 additions & 17 deletions osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Skinning;
using osuTK;

namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
public partial class LegacyCatcherNew : CompositeDrawable
public partial class LegacyCatcherNew : LegacyCatcher
{
[Resolved]
private Bindable<CatcherAnimationState> currentState { get; set; } = null!;
Expand All @@ -23,25 +21,12 @@ public partial class LegacyCatcherNew : CompositeDrawable

private Drawable currentDrawable = null!;

public LegacyCatcherNew()
{
RelativeSizeAxes = Axes.Both;
}

[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
foreach (var state in Enum.GetValues<CatcherAnimationState>())
{
AddInternal(drawables[state] = getDrawableFor(state).With(d =>
{
d.Anchor = Anchor.TopCentre;
d.Origin = Anchor.TopCentre;
d.RelativeSizeAxes = Axes.Both;
d.Size = Vector2.One;
d.FillMode = FillMode.Fit;
d.Alpha = 0;
}));
AddInternal(drawables[state] = getDrawableFor(state).With(d => d.Alpha = 0));
}

currentDrawable = drawables[CatcherAnimationState.Idle];
Expand Down
15 changes: 3 additions & 12 deletions osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,21 @@

using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Skinning;
using osuTK;

namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
public partial class LegacyCatcherOld : CompositeDrawable
public partial class LegacyCatcherOld : LegacyCatcher
{
public LegacyCatcherOld()
{
RelativeSizeAxes = Axes.Both;
AutoSizeAxes = Axes.Both;
}

[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
InternalChild = (skin.GetAnimation(@"fruit-ryuuta", true, true, true) ?? Empty()).With(d =>
{
d.Anchor = Anchor.TopCentre;
d.Origin = Anchor.TopCentre;
d.RelativeSizeAxes = Axes.Both;
d.Size = Vector2.One;
d.FillMode = FillMode.Fit;
});
InternalChild = skin.GetAnimation(@"fruit-ryuuta", true, true, true) ?? Empty();
}
}
}
37 changes: 24 additions & 13 deletions osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ public partial class CatchPlayfieldAdjustmentContainer : PlayfieldAdjustmentCont

public CatchPlayfieldAdjustmentContainer()
{
// because we are using centre anchor/origin, we will need to limit visibility in the future
// to ensure tall windows do not get a readability advantage.
// it may be possible to bake the catch-specific offsets (-100..340 mentioned below) into new values
// which are compatible with TopCentre alignment.
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;

// playfields in stable are positioned vertically at three fourths the difference between the playfield height and the window height in stable.
// we can match that in lazer by using relative coordinates for Y and considering window height to be 1, and playfield height to be 0.8.
RelativePositionAxes = Axes.Y;
Y = (1 - playfield_size_adjust) / 4 * 3;

Size = new Vector2(playfield_size_adjust);

Expand All @@ -42,18 +43,28 @@ public CatchPlayfieldAdjustmentContainer()
/// </summary>
private partial class ScalingContainer : Container
{
public ScalingContainer()
{
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
}

protected override void Update()
{
base.Update();

// in stable, fruit fall vertically from -100 to 340.
// to emulate this, we want to make our playfield 440 gameplay pixels high.
// we then offset it -100 vertically in the position set below.
const float stable_v_offset_ratio = 440 / 384f;
// in stable, fruit fall vertically from 100 pixels above the playfield top down to the catcher's Y position (i.e. -100 to 340),
// see: https://github.com/peppy/osu-stable-reference/blob/1531237b63392e82c003c712faa028406073aa8f/osu!/GameplayElements/HitObjects/Fruits/HitCircleFruits.cs#L65
// we already have the playfield positioned similar to stable (see CatchPlayfieldAdjustmentContainer constructor),
// so we only need to increase this container's height 100 pixels above the playfield, and offset it to have the bottom at 340 rather than 384.
const float stable_fruit_start_position = -100;
const float stable_catcher_y_position = 340;
const float playfield_v_size_adjustment = (stable_catcher_y_position - stable_fruit_start_position) / CatchPlayfield.HEIGHT;
const float playfield_v_catcher_offset = stable_catcher_y_position - CatchPlayfield.HEIGHT;

Scale = new Vector2(Parent.ChildSize.X / CatchPlayfield.WIDTH);
Position = new Vector2(0, -100 * stable_v_offset_ratio + Scale.X);
Size = Vector2.Divide(new Vector2(1, stable_v_offset_ratio), Scale);
Scale = new Vector2(Parent!.ChildSize.X / CatchPlayfield.WIDTH);
Position = new Vector2(0f, playfield_v_catcher_offset * Scale.Y);
Size = Vector2.Divide(new Vector2(1, playfield_v_size_adjustment), Scale);
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions osu.Game.Rulesets.Catch/UI/Catcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ public partial class Catcher : SkinReloadableDrawable
/// <summary>
/// The size of the catcher at 1x scale.
/// </summary>
/// <remarks>
/// This is mainly used to compute catching range, the actual catcher size may differ based on skin implementation and sprite textures.
/// This is also equivalent to the "catcherWidth" property in osu-stable when the game field and beatmap difficulty are set to default values.
/// </remarks>
/// <seealso cref="CatchPlayfield.WIDTH"/>
/// <seealso cref="CatchPlayfield.HEIGHT"/>
/// <seealso cref="IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY"/>
public const float BASE_SIZE = 106.75f;

/// <summary>
Expand Down
5 changes: 2 additions & 3 deletions osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Skinning.Default;
using osu.Game.Skinning;
using osuTK;

namespace osu.Game.Rulesets.Catch.UI
{
Expand All @@ -26,8 +25,8 @@ public SkinnableCatcher()
: base(new CatchSkinComponentLookup(CatchSkinComponents.Catcher), _ => new DefaultCatcher())
{
Anchor = Anchor.TopCentre;
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
OriginPosition = new Vector2(0.5f, 0.06f) * Catcher.BASE_SIZE;
Origin = Anchor.TopCentre;
CentreComponent = false;
}
}
}
53 changes: 28 additions & 25 deletions osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
using osu.Game.Rulesets.Scoring.Legacy;
using osu.Game.Utils;
using osuTK;

Expand Down Expand Up @@ -43,39 +44,41 @@ public ManiaBeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
: base(beatmap, ruleset)
{
IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo);
TargetColumns = GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmap(beatmap));

double roundedCircleSize = Math.Round(beatmap.Difficulty.CircleSize);
double roundedOverallDifficulty = Math.Round(beatmap.Difficulty.OverallDifficulty);

if (IsForCurrentRuleset)
if (IsForCurrentRuleset && TargetColumns > ManiaRuleset.MAX_STAGE_KEYS)
{
TargetColumns = GetColumnCountForNonConvert(beatmap.BeatmapInfo);

if (TargetColumns > ManiaRuleset.MAX_STAGE_KEYS)
{
TargetColumns /= 2;
Dual = true;
}
}
else
{
float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasDuration) / beatmap.HitObjects.Count;
if (percentSliderOrSpinner < 0.2)
TargetColumns = 7;
else if (percentSliderOrSpinner < 0.3 || roundedCircleSize >= 5)
TargetColumns = roundedOverallDifficulty > 5 ? 7 : 6;
else if (percentSliderOrSpinner > 0.6)
TargetColumns = roundedOverallDifficulty > 4 ? 5 : 4;
else
TargetColumns = Math.Max(4, Math.Min((int)roundedOverallDifficulty + 1, 7));
TargetColumns /= 2;
Dual = true;
}

originalTargetColumns = TargetColumns;
}

public static int GetColumnCountForNonConvert(BeatmapInfo beatmapInfo)
public static int GetColumnCount(LegacyBeatmapConversionDifficultyInfo difficulty)
{
if (new ManiaRuleset().RulesetInfo.Equals(difficulty.SourceRuleset))
return GetColumnCountForNonConvert(difficulty);

double roundedCircleSize = Math.Round(difficulty.CircleSize);
double roundedOverallDifficulty = Math.Round(difficulty.OverallDifficulty);

int countSliderOrSpinner = difficulty.TotalObjectCount - difficulty.CircleCount;
float percentSpecialObjects = (float)countSliderOrSpinner / difficulty.TotalObjectCount;

if (percentSpecialObjects < 0.2)
return 7;
if (percentSpecialObjects < 0.3 || roundedCircleSize >= 5)
return roundedOverallDifficulty > 5 ? 7 : 6;
if (percentSpecialObjects > 0.6)
return roundedOverallDifficulty > 4 ? 5 : 4;

return Math.Max(4, Math.Min((int)roundedOverallDifficulty + 1, 7));
}

public static int GetColumnCountForNonConvert(IBeatmapDifficultyInfo difficulty)
{
double roundedCircleSize = Math.Round(beatmapInfo.Difficulty.CircleSize);
double roundedCircleSize = Math.Round(difficulty.CircleSize);
return (int)Math.Max(1, roundedCircleSize);
}

Expand Down

0 comments on commit 063623b

Please sign in to comment.