// 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.Linq; using System.Threading; using osu.Framework.Bindables; using osu.Game.Audio; using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Taiko.Objects { /// <summary> /// Base class for taiko hitobjects that can become strong (large). /// </summary> public abstract class TaikoStrongableHitObject : TaikoHitObject { /// <summary> /// Scale multiplier for a strong drawable taiko hit object. /// </summary> public const float STRONG_SCALE = 1.4f; /// <summary> /// Default size of a strong drawable taiko hit object. /// </summary> public const float DEFAULT_STRONG_SIZE = DEFAULT_SIZE * STRONG_SCALE; public readonly Bindable<bool> IsStrongBindable = new BindableBool(); /// <summary> /// Whether this HitObject is a "strong" type. /// Strong hit objects give more points for hitting the hit object with both keys. /// </summary> public bool IsStrong { get => IsStrongBindable.Value; set => IsStrongBindable.Value = value; } protected TaikoStrongableHitObject() { IsStrongBindable.BindValueChanged(_ => updateSamplesFromType()); SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples()); } private void updateTypeFromSamples() { IsStrong = getStrongSamples().Any(); } private void updateSamplesFromType() { var strongSamples = getStrongSamples(); if (IsStrongBindable.Value != strongSamples.Any()) { if (IsStrongBindable.Value) Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_FINISH)); else { foreach (var sample in strongSamples) Samples.Remove(sample); } } } private HitSampleInfo[] getStrongSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_FINISH).ToArray(); protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { base.CreateNestedHitObjects(cancellationToken); if (IsStrong) AddNested(CreateStrongNestedHit(this.GetEndTime())); } /// <summary> /// Creates a <see cref="StrongNestedHitObject"/> representing a second hit on this object. /// This is only called if <see cref="IsStrong"/> is true. /// </summary> /// <param name="startTime">The start time of the nested hit.</param> protected abstract StrongNestedHitObject CreateStrongNestedHit(double startTime); } }