diff --git a/YARG.Core/Engine/Guitar/Engines/YargFiveFretEngine.cs b/YARG.Core/Engine/Guitar/Engines/YargFiveFretEngine.cs index c966d00e4..76cd8e5b6 100644 --- a/YARG.Core/Engine/Guitar/Engines/YargFiveFretEngine.cs +++ b/YARG.Core/Engine/Guitar/Engines/YargFiveFretEngine.cs @@ -27,12 +27,12 @@ protected override void UpdateBot(double time) return; } - LastButtonMask = ButtonMask; - ButtonMask = (byte) note.NoteMask; + LastButtonMask = EffectiveButtonMask; + EffectiveButtonMask = (byte) note.NoteMask; - YargLogger.LogFormatTrace("[Bot] Set button mask to: {0}", ButtonMask); + YargLogger.LogFormatTrace("[Bot] Set button mask to: {0}", EffectiveButtonMask); - HasTapped = ButtonMask != LastButtonMask; + HasTapped = EffectiveButtonMask != LastButtonMask; IsFretPress = true; HasStrummed = false; StrumLeniencyTimer.Start(time); @@ -48,15 +48,15 @@ protected override void UpdateBot(double time) if (sustainNote.IsDisjoint) { - ButtonMask |= (byte) sustainNote.DisjointMask; + EffectiveButtonMask |= (byte) sustainNote.DisjointMask; - YargLogger.LogFormatTrace("[Bot] Added Disjoint Sustain Mask {0} to button mask. {1}", sustainNote.DisjointMask, ButtonMask); + YargLogger.LogFormatTrace("[Bot] Added Disjoint Sustain Mask {0} to button mask. {1}", sustainNote.DisjointMask, EffectiveButtonMask); } else { - ButtonMask |= (byte) sustainNote.NoteMask; + EffectiveButtonMask |= (byte) sustainNote.NoteMask; - YargLogger.LogFormatTrace("[Bot] Added Sustain Mask {0} to button mask. {1}", sustainNote.NoteMask, ButtonMask); + YargLogger.LogFormatTrace("[Bot] Added Sustain Mask {0} to button mask. {1}", sustainNote.NoteMask, EffectiveButtonMask); } } } @@ -81,26 +81,26 @@ protected override void MutateStateWithInput(GameInput gameInput) } else if (IsFretInput(gameInput)) { - LastButtonMask = ButtonMask; + LastButtonMask = EffectiveButtonMask; HasFretted = true; IsFretPress = gameInput.Button; ToggleFret(gameInput.Action, gameInput.Button); // No other frets are held, enable the "open fret" - if ((ButtonMask & ~OPEN_MASK) == 0) + if ((EffectiveButtonMask & ~OPEN_MASK) == 0) { - ButtonMask |= OPEN_MASK; + EffectiveButtonMask |= OPEN_MASK; } else { // Some frets are held, disable the "open fret" - ButtonMask &= unchecked((byte) ~OPEN_MASK); + EffectiveButtonMask &= unchecked((byte) ~OPEN_MASK); } } YargLogger.LogFormatTrace("Mutated input state: Button Mask: {0}, HasFretted: {1}, HasStrummed: {2}", - ButtonMask, HasFretted, HasStrummed); + EffectiveButtonMask, HasFretted, HasStrummed); } protected override void UpdateHitLogic(double time) @@ -222,7 +222,7 @@ protected override void CheckForNoteHit() if (!CanNoteBeHit(note)) { YargLogger.LogFormatTrace("Cant hit note (Index: {0}, Mask {1}) at {2}. Buttons: {3}", i, - note.NoteMask, CurrentTime, ButtonMask); + note.NoteMask, CurrentTime, EffectiveButtonMask); // This does nothing special, it's just logging strum leniency if (isFirstNoteInWindow && HasStrummed && StrumLeniencyTimer.IsActive) { @@ -243,7 +243,7 @@ protected override void CheckForNoteHit() // Defines whether solo tapping is allowed // Only if SoloTaps engine parameter is set, solo is active, and no non-solo buttons are pressed // Also allow tap if the note is a solo start note, since IsSoloActive isn't set until after this point - bool SoloTapAllowed = EngineParameters.SoloTaps && (IsSoloActive || note.IsSoloStart) && !(StandardButtonCount > 0); + bool SoloTapAllowed = EngineParameters.SoloTaps && (IsSoloActive || note.IsSoloStart) && !StandardButtonHeld; // Handles hitting a hopo notes // If first note is a hopo then it can be hit without combo (for practice mode) @@ -290,7 +290,7 @@ protected override void CheckForNoteHit() protected override bool CanNoteBeHit(GuitarNote note) { - byte buttonsMasked = ButtonMask; + ushort buttonsMasked = EffectiveButtonMask; if (ActiveSustains.Count > 0) { foreach (var sustain in ActiveSustains) @@ -315,7 +315,7 @@ protected override bool CanNoteBeHit(GuitarNote note) // If the resulting masked buttons are 0, we need to apply the Open Mask so open notes can be hit // Need to make a copy of the button mask to prevent modifying the original - byte buttonMaskCopy = ButtonMask; + ushort buttonMaskCopy = EffectiveButtonMask; if (buttonsMasked == 0) { buttonsMasked |= OPEN_MASK; @@ -330,9 +330,9 @@ protected override bool CanNoteBeHit(GuitarNote note) } // If masked/extended sustain logic didn't work, try original ButtonMask - return IsNoteHittable(note, ButtonMask); + return IsNoteHittable(note, EffectiveButtonMask); - static bool IsNoteHittable(GuitarNote note, byte buttonsMasked) + static bool IsNoteHittable(GuitarNote note, ushort buttonsMasked) { // Only used for sustain logic bool useDisjointSustainMask = note is { IsDisjoint: true, WasHit: true }; @@ -423,8 +423,9 @@ static bool IsNoteHittable(GuitarNote note, byte buttonsMasked) protected override void HitNote(GuitarNote note) { - // Hopo leniency needs to activate on solo taps also - bool SoloTapAllowed = EngineParameters.SoloTaps && (IsSoloActive || note.IsSoloStart) && !(StandardButtonCount > 0); + // Defines whether solo tapping is allowed + // Only if SoloTaps engine parameter is set, solo is active, and no non-solo buttons are pressed + bool SoloTapAllowed = EngineParameters.SoloTaps && (IsSoloActive || note.IsSoloStart) && !StandardButtonHeld; if (note.IsHopo || note.IsTap || SoloTapAllowed) { @@ -500,10 +501,10 @@ protected bool CheckForGhostInput(GuitarNote note) } // Input is a hammer-on if the highest fret held is higher than the highest fret of the previous mask - bool isHammerOn = GetMostSignificantBit(ButtonMask) > GetMostSignificantBit(LastButtonMask); + bool isHammerOn = GetMostSignificantBit(EffectiveButtonMask) > GetMostSignificantBit(LastButtonMask); // Input is a hammer-on and the button pressed is not part of the note mask (incorrect fret) - if (isHammerOn && (ButtonMask & note.NoteMask) == 0) + if (isHammerOn && (EffectiveButtonMask & note.NoteMask) == 0) { return true; } diff --git a/YARG.Core/Engine/Guitar/GuitarEngine.cs b/YARG.Core/Engine/Guitar/GuitarEngine.cs index d39aef29c..1b272d166 100644 --- a/YARG.Core/Engine/Guitar/GuitarEngine.cs +++ b/YARG.Core/Engine/Guitar/GuitarEngine.cs @@ -9,19 +9,18 @@ public abstract class GuitarEngine : BaseEngine { protected const byte OPEN_MASK = 64; + // Mask of all the solo buttons in bit math + protected const ushort SOLO_MASK = 31744; public delegate void OverstrumEvent(); public OverstrumEvent? OnOverstrum; - public byte ButtonMask { get; protected set; } = OPEN_MASK; - + public byte EffectiveButtonMask { get; protected set; } = OPEN_MASK; + public ushort InputButtonMask { get; protected set; } public byte LastButtonMask { get; protected set; } - public byte SoloButtonMask { get; protected set; } = OPEN_MASK; - - // Count of standard buttons currently pressed - public int StandardButtonCount { get; protected set; } = 0; + public bool StandardButtonHeld { get; private set; } protected bool HasFretted; protected bool HasStrummed; @@ -88,9 +87,9 @@ protected override void GenerateQueuedUpdates(double nextTime) public override void Reset(bool keepCurrentButtons = false) { - byte buttons = ButtonMask; + byte buttons = EffectiveButtonMask; - ButtonMask = OPEN_MASK; + EffectiveButtonMask = OPEN_MASK; HasFretted = false; HasStrummed = false; @@ -109,7 +108,7 @@ public override void Reset(bool keepCurrentButtons = false) if (keepCurrentButtons) { - ButtonMask = buttons; + EffectiveButtonMask = buttons; } } @@ -170,7 +169,7 @@ protected override bool CanSustainHold(GuitarNote note) { var mask = note.IsDisjoint ? note.DisjointMask : note.NoteMask; - var buttonsMasked = ButtonMask; + var buttonsMasked = EffectiveButtonMask; if ((mask & OPEN_MASK) != 0) { buttonsMasked |= OPEN_MASK; @@ -363,32 +362,20 @@ protected sealed override int CalculateBaseScore() protected void ToggleFret(int fret, bool active) { - // FIXME: This is a terrible hack - if((int) fret >= 10) { - fret -= 10; - } else { - if (active) - { - // Add one to count of standard buttons pressed, avoiding overflow - StandardButtonCount = (StandardButtonCount < int.MaxValue) ? StandardButtonCount + 1 : StandardButtonCount; - } - else - { - // Subtract one from count, avoiding underflow - StandardButtonCount = (StandardButtonCount > 0) ? StandardButtonCount - 1 : 0; - } - } - ButtonMask = (byte) (active ? ButtonMask | (1 << fret) : ButtonMask & ~(1 << fret)); + InputButtonMask = (ushort) (active ? InputButtonMask | (1 << fret) : InputButtonMask & ~(1 << fret)); + + // What we're doing here is transposing bits 10-14 of the input mask down to 0-4 of the effective mask + // used elsewhere so that solo buttons are treated as if they were regular buttons + byte soloButtonMask = (byte) (InputButtonMask >> 10); + + // EffectiveButtonMask is the bitwise or of the low 8 bits of InputButtonMask and soloButtonMask + EffectiveButtonMask = (byte) (InputButtonMask | soloButtonMask); + StandardButtonHeld = (InputButtonMask & ~OPEN_MASK & ~SOLO_MASK) > 0; } public bool IsFretHeld(GuitarAction fret) { - // FIXME: This is a terrible hack - if((int) fret >= 10) - { - fret -= 10; - } - return (ButtonMask & (1 << (int) fret)) != 0; + return (EffectiveButtonMask & (1 << (int) fret)) != 0; } protected static bool IsFretInput(GameInput input)