Beispiel #1
0
        public JudgeResult?UserPressed(time_t timeStamp)
        {
            if (AutoPlay)
            {
                return(null);
            }

            m_userHeld = true;
            m_userWhen = timeStamp;

            if (m_ticks.Count == 0)
            {
                return(null);
            }

            var tick = m_ticks[0];

            // Don't ACTUALLY handle holds handled in here
            if (tick.IsHold)
            {
                OnHoldPressed?.Invoke(timeStamp, tick.AssociatedObject);
                m_lastPressedObject = tick.AssociatedObject;
                return(null);
            }
            else
            {
                OnChipPressed?.Invoke(timeStamp, tick.AssociatedObject);
            }

            m_ticks.RemoveAt(0);

            time_t diff    = tick.Position + JudgementOffset - timeStamp;
            time_t absDiff = MathL.Abs(diff.Seconds);

            time_t offsetTime = timeStamp - JudgementOffset;

            JudgeResult result;

            if (absDiff <= PERF_RADIUS)
            {
                result = new JudgeResult(diff, JudgeKind.Perfect);
            }
            else if (absDiff <= CRIT_RADIUS)
            {
                result = new JudgeResult(diff, JudgeKind.Critical);
            }
            else if (absDiff <= NEAR_RADIUS)
            {
                result = new JudgeResult(diff, JudgeKind.Near);
            }
            // TODO(local): Is this how we want to handle misses?
            else
            {
                result = new JudgeResult(diff, JudgeKind.Bad);
            }

            OnTickProcessed?.Invoke(tick.AssociatedObject, offsetTime, result);
            return(result);
        }
Beispiel #2
0
        public JudgeResult?UserPressed(time_t position)
        {
            // This check just makes sure that we can process ticks.
            // If there are no state ticks, there should never be score ticks left.
            if (HasStateTicks)
            {
                Debug.Assert(HasScoreTicks);
            }
            else
            {
                SpawnKeyBeam?.Invoke(Label, JudgeKind.Passive, false);
                return(null);
            }

            switch (m_state)
            {
            case JudgeState.Idle:
            {
                var nextStateTick = NextStateTick;

                time_t difference    = position - (nextStateTick.Position + JudgementOffset);
                time_t absDifference = Math.Abs((double)difference);

                if (nextStateTick.State == JudgeState.ChipAwaitPress && absDifference <= m_chipMissRadius)
                {
                    var scoreTick = NextScoreTick;

                    Debug.Assert(scoreTick.Kind == TickKind.Chip);
                    Debug.Assert(scoreTick.Position == nextStateTick.Position);

                    // `difference` applies to both ticks, don't recalculate

                    JudgeResult result;
                    if (absDifference <= m_chipPerfectRadius)
                    {
                        result = new JudgeResult(difference, JudgeKind.Perfect);
                    }
                    else if (absDifference <= m_chipCriticalRadius)
                    {
                        result = new JudgeResult(difference, JudgeKind.Critical);
                    }
                    else if (absDifference <= m_chipNearRadius)
                    {
                        result = new JudgeResult(difference, JudgeKind.Near);
                    }
                    // TODO(local): Is this how we want to handle misses?
                    else
                    {
                        result = new JudgeResult(difference, JudgeKind.Bad);
                    }

                    OnTickProcessed?.Invoke(scoreTick.Entity, position, result, difference < 0);
                    OnChipPressed?.Invoke(position, scoreTick.Entity);
                    SpawnKeyBeam?.Invoke(scoreTick.Entity.Lane, result.Kind, difference < 0);

                    AdvanceStateTick();
                    AdvanceScoreTick();

                    // state stays idle after a chip press, chips are instantaneous

                    IsBeingPlayed = true;

                    return(result);
                }
                else if (nextStateTick.State == JudgeState.HoldAwaitPress && absDifference <= m_holdActivateRadius)
                {
                    OnHoldPressed?.Invoke(position, nextStateTick.Entity);

                    AdvanceStateTick();
                    // No need to advance a score tick, we haven't judged anything

                    // state is `hold on` because ofc we pressed the hold!
                    m_state            = JudgeState.HoldOn;
                    m_currentStateTick = nextStateTick;

                    IsBeingPlayed = true;
                }

                // do nothing when pressed otherwise
                else
                {
                    SpawnKeyBeam?.Invoke(Label, JudgeKind.Passive, false);
                }
            } break;

            case JudgeState.HoldOff:
            {
                OnHoldPressed?.Invoke(position, m_currentStateTick.Entity);

                m_state = JudgeState.HoldOn;

                IsBeingPlayed = true;
            } break;

            case JudgeState.HoldOn: throw new InvalidOperationException();
            }

            return(null);
        }
Beispiel #3
0
        protected override void AdvancePosition(time_t position)
        {
            // remove old ticks first
            while (!AutoPlay && m_ticks.Count > 0)
            {
                var tick = m_ticks[0];

                time_t radius = tick.IsHold ? HOLD_RADIUS : MAX_RADIUS;
                if (tick.Position + JudgementOffset < position - radius)
                {
                    m_ticks.RemoveAt(0);
                    OnTickProcessed?.Invoke(tick.AssociatedObject, position, new JudgeResult(tick.Position + JudgementOffset - position, JudgeKind.Miss));
                }
                else
                {
                    break;
                }
            }

            while (m_ticks.Count > 0)
            {
                var tick = m_ticks[0];
                if (AutoPlay && position >= tick.Position)
                {
                    m_ticks.RemoveAt(0);
                    if (tick.IsAutoTick)
                    {
                        if (tick.Position == tick.AssociatedObject.AbsolutePosition)
                        {
                            OnHoldPressed?.Invoke(position, tick.AssociatedObject);
                        }
                        //else OnHoldReleased?.Invoke(position, tick.AssociatedObject);
                    }
                    else if (tick.IsHold)
                    {
                        OnTickProcessed?.Invoke(tick.AssociatedObject, position - JudgementOffset, new JudgeResult(0, JudgeKind.Passive));
                    }
                    else
                    {
                        OnChipPressed?.Invoke(position, tick.AssociatedObject);
                        OnTickProcessed?.Invoke(tick.AssociatedObject, tick.Position, new JudgeResult(0, JudgeKind.Perfect));
                    }
                }
                else // ===== NO AUTO PLAY =====
                {
                    if (!tick.IsHold)
                    {
                        break;
                    }

                    time_t check = tick.AssociatedObject.AbsolutePosition + JudgementOffset - m_userWhen;
                    if (check > MISS_RADIUS)
                    {
                        break;
                    }

                    time_t diff    = tick.Position + JudgementOffset - position;
                    time_t absDiff = MathL.Abs(diff.Seconds);

                    if (m_userHeld && diff > 0 && absDiff <= HOLD_RADIUS)
                    {
                        m_ticks.RemoveAt(0);
                        OnTickProcessed?.Invoke(tick.AssociatedObject, position - JudgementOffset, new JudgeResult(diff, JudgeKind.Passive));
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }