2022-09-15 15:02:57 +08:00
|
|
|
// 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 System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using JetBrains.Annotations;
|
|
|
|
using osu.Framework.Audio.Sample;
|
|
|
|
using osu.Framework.Bindables;
|
|
|
|
using osu.Framework.Graphics;
|
|
|
|
using osu.Framework.Graphics.Textures;
|
|
|
|
using osu.Game.Audio;
|
|
|
|
using osu.Game.Beatmaps.Formats;
|
|
|
|
using osu.Game.Extensions;
|
|
|
|
using osu.Game.IO;
|
2023-06-15 03:15:12 +08:00
|
|
|
using osu.Game.Screens.Play;
|
2022-09-15 15:02:57 +08:00
|
|
|
using osu.Game.Screens.Play.HUD;
|
|
|
|
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
2023-11-10 11:58:07 +08:00
|
|
|
using osu.Game.Skinning.Components;
|
2022-09-15 15:02:57 +08:00
|
|
|
using osuTK;
|
|
|
|
using osuTK.Graphics;
|
|
|
|
|
|
|
|
namespace osu.Game.Skinning
|
|
|
|
{
|
|
|
|
public class ArgonSkin : Skin
|
|
|
|
{
|
|
|
|
public static SkinInfo CreateInfo() => new SkinInfo
|
|
|
|
{
|
2022-11-09 12:44:59 +08:00
|
|
|
ID = Skinning.SkinInfo.ARGON_SKIN,
|
2022-09-15 15:02:57 +08:00
|
|
|
Name = "osu! \"argon\" (2022)",
|
|
|
|
Creator = "team osu!",
|
|
|
|
Protected = true,
|
|
|
|
InstantiationInfo = typeof(ArgonSkin).GetInvariantInstantiationInfo()
|
|
|
|
};
|
|
|
|
|
2022-12-12 14:52:29 +08:00
|
|
|
protected readonly IStorageResourceProvider Resources;
|
2022-09-15 15:02:57 +08:00
|
|
|
|
|
|
|
public ArgonSkin(IStorageResourceProvider resources)
|
|
|
|
: this(CreateInfo(), resources)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)]
|
|
|
|
public ArgonSkin(SkinInfo skin, IStorageResourceProvider resources)
|
2023-10-22 08:27:21 +08:00
|
|
|
: base(
|
|
|
|
skin,
|
2023-11-14 21:01:56 +08:00
|
|
|
resources
|
2023-10-22 08:27:21 +08:00
|
|
|
)
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
2022-12-12 14:52:29 +08:00
|
|
|
Resources = resources;
|
2022-09-22 18:16:49 +08:00
|
|
|
|
|
|
|
Configuration.CustomComboColours = new List<Color4>
|
|
|
|
{
|
|
|
|
// Standard combo progression order is green - blue - red - yellow.
|
|
|
|
// But for whatever reason, this starts from index 1, not 0.
|
|
|
|
//
|
|
|
|
// We've added two new combo colours in argon, so to ensure the initial rotation matches,
|
|
|
|
// this same progression is in slots 1 - 4.
|
|
|
|
|
|
|
|
// Orange
|
|
|
|
new Color4(241, 116, 0, 255),
|
|
|
|
// Green
|
|
|
|
new Color4(0, 241, 53, 255),
|
|
|
|
// Blue
|
|
|
|
new Color4(0, 82, 241, 255),
|
|
|
|
// Red
|
|
|
|
new Color4(241, 0, 0, 255),
|
|
|
|
// Yellow
|
|
|
|
new Color4(232, 235, 0, 255),
|
|
|
|
// Purple
|
|
|
|
new Color4(92, 0, 241, 255),
|
|
|
|
};
|
2022-09-15 15:02:57 +08:00
|
|
|
}
|
|
|
|
|
2022-11-09 12:44:59 +08:00
|
|
|
public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Textures?.Get(componentName, wrapModeS, wrapModeT);
|
2022-09-15 15:02:57 +08:00
|
|
|
|
2022-11-09 12:44:59 +08:00
|
|
|
public override ISample? GetSample(ISampleInfo sampleInfo)
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
|
|
|
foreach (string lookup in sampleInfo.LookupNames)
|
|
|
|
{
|
2022-12-12 14:52:29 +08:00
|
|
|
var sample = Samples?.Get(lookup) ?? Resources.AudioManager?.Samples.Get(lookup);
|
2022-09-15 15:02:57 +08:00
|
|
|
if (sample != null)
|
|
|
|
return sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-11-09 15:04:56 +08:00
|
|
|
public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup)
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
2022-11-13 11:46:20 +08:00
|
|
|
// Temporary until default skin has a valid hit lighting.
|
|
|
|
if ((lookup as SkinnableSprite.SpriteComponentLookup)?.LookupName == @"lighting") return Drawable.Empty();
|
|
|
|
|
2022-11-09 13:11:41 +08:00
|
|
|
if (base.GetDrawableComponent(lookup) is Drawable c)
|
2022-09-15 15:02:57 +08:00
|
|
|
return c;
|
|
|
|
|
2022-11-09 13:11:41 +08:00
|
|
|
switch (lookup)
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
2023-02-16 14:33:56 +08:00
|
|
|
case SkinComponentsContainerLookup containerLookup:
|
2023-02-17 17:22:10 +08:00
|
|
|
// Only handle global level defaults for now.
|
|
|
|
if (containerLookup.Ruleset != null)
|
|
|
|
return null;
|
|
|
|
|
2023-02-16 14:33:56 +08:00
|
|
|
switch (containerLookup.Target)
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
2023-02-15 17:31:55 +08:00
|
|
|
case SkinComponentsContainerLookup.TargetArea.SongSelect:
|
2023-02-15 16:24:34 +08:00
|
|
|
var songSelectComponents = new DefaultSkinComponentsContainer(_ =>
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
|
|
|
// do stuff when we need to.
|
|
|
|
});
|
|
|
|
|
|
|
|
return songSelectComponents;
|
|
|
|
|
2023-02-15 17:31:55 +08:00
|
|
|
case SkinComponentsContainerLookup.TargetArea.MainHUDComponents:
|
2023-02-15 16:24:34 +08:00
|
|
|
var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container =>
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
2023-10-06 17:46:50 +08:00
|
|
|
var health = container.OfType<ArgonHealthDisplay>().FirstOrDefault();
|
2023-11-10 15:04:28 +08:00
|
|
|
var healthLine = container.OfType<BoxElement>().FirstOrDefault();
|
2023-11-10 15:43:47 +08:00
|
|
|
var wedgePieces = container.OfType<ArgonWedgePiece>().ToArray();
|
2023-10-26 14:12:24 +08:00
|
|
|
var score = container.OfType<ArgonScoreCounter>().FirstOrDefault();
|
|
|
|
var accuracy = container.OfType<ArgonAccuracyCounter>().FirstOrDefault();
|
|
|
|
var combo = container.OfType<ArgonComboCounter>().FirstOrDefault();
|
2023-01-10 04:59:48 +08:00
|
|
|
var songProgress = container.OfType<ArgonSongProgress>().FirstOrDefault();
|
2023-06-15 03:15:12 +08:00
|
|
|
var keyCounter = container.OfType<ArgonKeyCounterDisplay>().FirstOrDefault();
|
2022-09-15 15:02:57 +08:00
|
|
|
|
2023-10-26 14:12:24 +08:00
|
|
|
if (health != null)
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
|
|
|
// elements default to beneath the health bar
|
2023-10-26 14:12:24 +08:00
|
|
|
const float components_x_offset = 50;
|
2022-09-15 15:02:57 +08:00
|
|
|
|
2023-11-07 05:48:51 +08:00
|
|
|
health.Anchor = Anchor.TopLeft;
|
|
|
|
health.Origin = Anchor.TopLeft;
|
2023-11-07 07:03:16 +08:00
|
|
|
health.UseRelativeSize.Value = false;
|
2023-11-11 19:15:49 +08:00
|
|
|
health.Width = 300;
|
2023-11-07 05:48:51 +08:00
|
|
|
health.BarHeight.Value = 30f;
|
|
|
|
health.Position = new Vector2(components_x_offset, 20f);
|
2022-09-15 15:02:57 +08:00
|
|
|
|
2023-11-08 07:06:51 +08:00
|
|
|
if (healthLine != null)
|
2023-11-10 13:03:24 +08:00
|
|
|
{
|
|
|
|
healthLine.Anchor = Anchor.TopLeft;
|
|
|
|
healthLine.Origin = Anchor.CentreLeft;
|
|
|
|
healthLine.Y = health.Y + ArgonHealthDisplay.MAIN_PATH_RADIUS;
|
|
|
|
healthLine.Size = new Vector2(45, 3);
|
|
|
|
}
|
2023-11-08 07:06:51 +08:00
|
|
|
|
2023-11-10 15:43:47 +08:00
|
|
|
foreach (var wedgePiece in wedgePieces)
|
|
|
|
wedgePiece.Position += new Vector2(-50, 15);
|
2023-10-26 14:12:24 +08:00
|
|
|
|
2023-11-10 15:43:47 +08:00
|
|
|
if (score != null)
|
|
|
|
{
|
|
|
|
score.Origin = Anchor.TopRight;
|
|
|
|
score.Position = new Vector2(components_x_offset + 200, wedgePieces.Last().Y + 30);
|
2023-11-08 06:48:21 +08:00
|
|
|
}
|
2023-10-26 14:12:24 +08:00
|
|
|
|
2023-11-08 06:48:21 +08:00
|
|
|
if (accuracy != null)
|
|
|
|
{
|
|
|
|
// +4 to vertically align the accuracy counter with the score counter.
|
|
|
|
accuracy.Position = new Vector2(-20, 20);
|
|
|
|
accuracy.Anchor = Anchor.TopRight;
|
|
|
|
accuracy.Origin = Anchor.TopRight;
|
2023-10-06 17:46:50 +08:00
|
|
|
}
|
|
|
|
|
2022-09-15 15:02:57 +08:00
|
|
|
var hitError = container.OfType<HitErrorMeter>().FirstOrDefault();
|
|
|
|
|
|
|
|
if (hitError != null)
|
|
|
|
{
|
|
|
|
hitError.Anchor = Anchor.CentreLeft;
|
|
|
|
hitError.Origin = Anchor.CentreLeft;
|
|
|
|
}
|
|
|
|
|
|
|
|
var hitError2 = container.OfType<HitErrorMeter>().LastOrDefault();
|
|
|
|
|
|
|
|
if (hitError2 != null)
|
|
|
|
{
|
|
|
|
hitError2.Anchor = Anchor.CentreRight;
|
|
|
|
hitError2.Scale = new Vector2(-1, 1);
|
|
|
|
// origin flipped to match scale above.
|
|
|
|
hitError2.Origin = Anchor.CentreLeft;
|
|
|
|
}
|
2023-01-10 04:59:48 +08:00
|
|
|
|
|
|
|
if (songProgress != null)
|
|
|
|
{
|
2023-06-26 15:20:51 +08:00
|
|
|
const float padding = 10;
|
2023-11-12 16:28:15 +08:00
|
|
|
// Hard to find this at runtime, so taken from the most expanded state during replay.
|
|
|
|
const float song_progress_offset_height = 36 + padding;
|
2023-06-26 15:20:51 +08:00
|
|
|
|
|
|
|
songProgress.Position = new Vector2(0, -padding);
|
2023-01-10 04:59:48 +08:00
|
|
|
songProgress.Scale = new Vector2(0.9f, 1);
|
2023-06-15 03:15:12 +08:00
|
|
|
|
2023-06-26 15:20:51 +08:00
|
|
|
if (keyCounter != null && hitError != null)
|
2023-06-15 03:15:12 +08:00
|
|
|
{
|
2023-06-26 15:22:38 +08:00
|
|
|
keyCounter.Anchor = Anchor.BottomRight;
|
|
|
|
keyCounter.Origin = Anchor.BottomRight;
|
|
|
|
keyCounter.Position = new Vector2(-(hitError.Width + padding), -(padding * 2 + song_progress_offset_height));
|
2023-06-15 03:15:12 +08:00
|
|
|
}
|
2023-11-07 06:58:26 +08:00
|
|
|
|
|
|
|
if (combo != null && hitError != null)
|
|
|
|
{
|
|
|
|
combo.Anchor = Anchor.BottomLeft;
|
|
|
|
combo.Origin = Anchor.BottomLeft;
|
2023-11-12 16:28:15 +08:00
|
|
|
combo.Position = new Vector2((hitError.Width + padding), -(padding * 2 + song_progress_offset_height));
|
2023-11-07 06:58:26 +08:00
|
|
|
}
|
2023-01-10 04:59:48 +08:00
|
|
|
}
|
2022-09-15 15:02:57 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
{
|
|
|
|
Children = new Drawable[]
|
|
|
|
{
|
2023-11-10 15:43:47 +08:00
|
|
|
new ArgonWedgePiece
|
|
|
|
{
|
|
|
|
Size = new Vector2(380, 72),
|
|
|
|
},
|
|
|
|
new ArgonWedgePiece
|
|
|
|
{
|
|
|
|
Size = new Vector2(380, 72),
|
|
|
|
Position = new Vector2(4, 5)
|
|
|
|
},
|
2023-11-16 13:18:49 +08:00
|
|
|
new ArgonScoreCounter
|
|
|
|
{
|
|
|
|
ShowLabel = { Value = false },
|
|
|
|
},
|
2023-11-08 07:07:24 +08:00
|
|
|
new ArgonHealthDisplay(),
|
2023-11-15 09:45:01 +08:00
|
|
|
new BoxElement
|
|
|
|
{
|
|
|
|
CornerRadius = { Value = 0.5f }
|
|
|
|
},
|
2023-10-26 14:12:24 +08:00
|
|
|
new ArgonAccuracyCounter(),
|
2023-11-12 16:28:15 +08:00
|
|
|
new ArgonComboCounter
|
|
|
|
{
|
|
|
|
Scale = new Vector2(1.3f)
|
|
|
|
},
|
2022-09-15 15:02:57 +08:00
|
|
|
new BarHitErrorMeter(),
|
|
|
|
new BarHitErrorMeter(),
|
2023-10-26 14:12:24 +08:00
|
|
|
new ArgonSongProgress(),
|
|
|
|
new ArgonKeyCounterDisplay(),
|
2022-09-15 15:02:57 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return skinnableTargetWrapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-11-09 12:44:59 +08:00
|
|
|
public override IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
|
2022-09-15 15:02:57 +08:00
|
|
|
{
|
|
|
|
// todo: this code is pulled from LegacySkin and should not exist.
|
|
|
|
// will likely change based on how databased storage of skin configuration goes.
|
|
|
|
switch (lookup)
|
|
|
|
{
|
|
|
|
case GlobalSkinColours global:
|
|
|
|
switch (global)
|
|
|
|
{
|
|
|
|
case GlobalSkinColours.ComboColours:
|
2023-09-06 16:37:17 +08:00
|
|
|
{
|
|
|
|
LogLookupDebug(this, lookup, LookupDebugType.Hit);
|
2022-11-09 12:44:59 +08:00
|
|
|
return SkinUtils.As<TValue>(new Bindable<IReadOnlyList<Color4>?>(Configuration.ComboColours));
|
2023-09-06 16:37:17 +08:00
|
|
|
}
|
2022-09-15 15:02:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SkinComboColourLookup comboColour:
|
2023-09-06 16:37:17 +08:00
|
|
|
LogLookupDebug(this, lookup, LookupDebugType.Hit);
|
2022-09-15 15:02:57 +08:00
|
|
|
return SkinUtils.As<TValue>(new Bindable<Color4>(getComboColour(Configuration, comboColour.ColourIndex)));
|
|
|
|
}
|
|
|
|
|
2023-09-06 16:37:17 +08:00
|
|
|
LogLookupDebug(this, lookup, LookupDebugType.Miss);
|
2022-09-15 15:02:57 +08:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Color4 getComboColour(IHasComboColours source, int colourIndex)
|
2023-08-16 18:34:37 +08:00
|
|
|
=> source.ComboColours![colourIndex % source.ComboColours.Count];
|
2022-09-15 15:02:57 +08:00
|
|
|
}
|
|
|
|
}
|