Переглянути джерело

Fix slider fat finger logic

Clément Wolf 1 місяць тому
батько
коміт
4ca361d6ef
3 змінених файлів з 34 додано та 36 видалено
  1. 6 15
      src/App/Osu/OsuBeatmap.cpp
  2. 27 20
      src/App/Osu/OsuSlider.cpp
  3. 1 1
      src/App/Osu/OsuSlider.h

+ 6 - 15
src/App/Osu/OsuBeatmap.cpp

@@ -1293,21 +1293,8 @@ bool OsuBeatmap::isKey2Down() {
     }
 }
 
-bool OsuBeatmap::isClickHeld() {
-    if(m_bIsWatchingReplay) {
-        return current_keys & (OsuReplay::M1 | OsuReplay::K1 | OsuReplay::M2 | OsuReplay::K2);
-    } else {
-        return m_bClick1Held || m_bClick2Held;
-    }
-}
-
-bool OsuBeatmap::isLastKeyDownKey1() {
-    if(m_bIsWatchingReplay) {
-        return last_keys & (OsuReplay::M1 | OsuReplay::K1);
-    } else {
-        return m_bPrevKeyWasKey1;
-    }
-}
+bool OsuBeatmap::isClickHeld() { return isKey1Down() || isKey2Down(); }
+bool OsuBeatmap::isLastKeyDownKey1() { return m_bPrevKeyWasKey1; }
 
 UString OsuBeatmap::getTitle() const {
     if(m_selectedDifficulty2 != NULL)
@@ -2498,11 +2485,13 @@ void OsuBeatmap::update2() {
 
             // Pressed key 1
             if(!(last_keys & OsuReplay::K1) && current_keys & OsuReplay::K1) {
+                m_bPrevKeyWasKey1 = true;
                 m_osu->getHUD()->animateInputoverlay(1, true);
                 m_clicks.push_back(click);
                 if(!m_bInBreak && !m_bIsInSkippableSection) m_osu->getScore()->addKeyCount(1);
             }
             if(!(last_keys & OsuReplay::M1) && current_keys & OsuReplay::M1) {
+                m_bPrevKeyWasKey1 = true;
                 m_osu->getHUD()->animateInputoverlay(3, true);
                 m_clicks.push_back(click);
                 if(!m_bInBreak && !m_bIsInSkippableSection) m_osu->getScore()->addKeyCount(3);
@@ -2510,11 +2499,13 @@ void OsuBeatmap::update2() {
 
             // Pressed key 2
             if(!(last_keys & OsuReplay::K2) && current_keys & OsuReplay::K2) {
+                m_bPrevKeyWasKey1 = false;
                 m_osu->getHUD()->animateInputoverlay(2, true);
                 m_clicks.push_back(click);
                 if(!m_bInBreak && !m_bIsInSkippableSection) m_osu->getScore()->addKeyCount(2);
             }
             if(!(last_keys & OsuReplay::M2) && current_keys & OsuReplay::M2) {
+                m_bPrevKeyWasKey1 = false;
                 m_osu->getHUD()->animateInputoverlay(4, true);
                 m_clicks.push_back(click);
                 if(!m_bInBreak && !m_bIsInSkippableSection) m_osu->getScore()->addKeyCount(4);

+ 27 - 20
src/App/Osu/OsuSlider.cpp

@@ -174,7 +174,7 @@ OsuSlider::OsuSlider(char type, int repeat, float pixelLength, std::vector<Vecto
     m_fEndHitAnimation = 0.0f;
     m_fEndSliderBodyFadeAnimation = 0.0f;
     m_iStrictTrackingModLastClickHeldTime = 0;
-    m_iDownKey = 0;
+    m_iFatFingerKey = 0;
     m_iPrevSliderSlideSoundSampleSet = -1;
     m_bCursorLeft = true;
     m_bCursorInside = false;
@@ -735,12 +735,9 @@ void OsuSlider::update(long curPos) {
         m_vCurPoint = m_beatmap->osuCoords2Pixels(m_vCurPointRaw);
     }
 
-    // reset sliding key (opposite), see isClickHeldSlider()
-    if(m_iDownKey > 0) {
-        if((m_iDownKey == 2 && !m_beatmap->isKey1Down()) ||
-           (m_iDownKey == 1 && !m_beatmap->isKey2Down()))  // opposite key!
-            m_iDownKey = 0;
-    }
+    // When fat finger key is released, remove isClickHeldSlider() restrictions
+    if(m_iFatFingerKey == 1 && !m_beatmap->isKey1Down()) m_iFatFingerKey = 0;
+    if(m_iFatFingerKey == 2 && !m_beatmap->isKey2Down()) m_iFatFingerKey = 0;
 
     // handle dynamic followradius
     float followRadius =
@@ -1179,11 +1176,16 @@ void OsuSlider::onHit(OsuScore::HIT result, long delta, bool startOrEnd, float t
 
         m_bStartFinished = true;
 
-        // remember which key this slider was started with
-        if(m_beatmap->isKey2Down() && !m_beatmap->isLastKeyDownKey1())
-            m_iDownKey = 2;
-        else if(m_beatmap->isKey1Down() && m_beatmap->isLastKeyDownKey1())
-            m_iDownKey = 1;
+        // The player entered the slider by fat fingering, so...
+        if(m_beatmap->isKey1Down() && m_beatmap->isKey2Down()) {
+            if(m_beatmap->isLastKeyDownKey1()) {
+                // Player pressed K1 last: "fat finger" key is K2
+                m_iFatFingerKey = 2;
+            } else {
+                // Player pressed K2 last: "fat finger" key is K1
+                m_iFatFingerKey = 1;
+            }
+        }
 
         if(!m_beatmap->getOsu()->getModTarget())
             m_beatmap->addHitResult(
@@ -1358,7 +1360,7 @@ void OsuSlider::onReset(long curPos) {
     m_beatmap->getSkin()->stopSliderSlideSound();
 
     m_iStrictTrackingModLastClickHeldTime = 0;
-    m_iDownKey = 0;
+    m_iFatFingerKey = 0;
     m_iPrevSliderSlideSoundSampleSet = -1;
     m_bCursorLeft = true;
     m_bHeldTillEnd = false;
@@ -1434,11 +1436,16 @@ void OsuSlider::rebuildVertexBuffer(bool useRawCoords) {
 }
 
 bool OsuSlider::isClickHeldSlider() {
-    // m_iDownKey contains the key the sliderstartcircle was clicked with (if it was clicked at all, if not then it is
-    // 0) it is reset back to 0 automatically in update() once the opposite key has been released at least once if
-    // m_iDownKey is less than 1, then any key being held is enough to slide (either the startcircle was missed, or the
-    // opposite key it was clicked with has been released at least once already) otherwise, that specific key is the
-    // only one which counts for sliding
-    const bool mouseDownAcceptable = (m_iDownKey == 1 ? m_beatmap->isKey1Down() : m_beatmap->isKey2Down());
-    return (m_iDownKey < 1 ? m_beatmap->isClickHeld() : mouseDownAcceptable);
+    // osu! has a weird slider quirk, that I'll explain in detail here.
+    // When holding K1 before the slider, tapping K2 on slider head, and releasing K2 later,
+    // the slider is no longer considered being "held" until K2 is pressed again, or K1 is released and pressed again.
+
+    // The reason this exists is to prevent people from holding K1 the whole map and tapping with K2.
+    // Holding is part of the rhythm flow, and this is a rhythm game right?
+
+    if(m_iFatFingerKey == 0) return m_beatmap->isClickHeld();
+    if(m_iFatFingerKey == 1) return m_beatmap->isKey2Down();
+    if(m_iFatFingerKey == 2) return m_beatmap->isKey1Down();
+
+    return false;  // unreachable
 }

+ 1 - 1
src/App/Osu/OsuSlider.h

@@ -128,7 +128,7 @@ class OsuSlider : public OsuHitObject {
     float m_fEndHitAnimation;
     float m_fEndSliderBodyFadeAnimation;
     long m_iStrictTrackingModLastClickHeldTime;
-    int m_iDownKey;
+    int m_iFatFingerKey;
     int m_iPrevSliderSlideSoundSampleSet;
     bool m_bCursorLeft;
     bool m_bCursorInside;