public void SetTickMethod(StateTick tick) { mTick = tick; }
protected override void AdvancePosition(time_t position) { time_t timeDelta = position - m_lastUpdatePosition; m_lastUpdatePosition = position; if (!HasStateTicks && !HasScoreTicks) { return; } switch (m_state) { case JudgeState.Idle: { var nextStateTick = NextStateTick; while (position - (nextStateTick.Position + JudgementOffset) >= 0) { if (nextStateTick.State == JudgeState.CursorReset) { AdvanceStateTick(); OnShowCursor?.Invoke(); CursorPosition = m_desiredCursorPosition = nextStateTick.RootEntity.InitialValue; LaserRange = nextStateTick.RootEntity.RangeExtended ? 2 : 1; m_direction = 0; } else if (nextStateTick.State == JudgeState.LaserBegin) { AdvanceStateTick(); //LastLockTime = position; m_direction = 0; m_state = nextStateTick.RootEntity.IsInstant ? (IsBeingPlayed ? JudgeState.ActiveOn : JudgeState.ActiveOff) : JudgeState.ActiveOn; m_currentStateTick = nextStateTick; // The first score tick happens at the same time as the laser start event, // hop straight over to the other case explicitly and let it process the score tick. goto case JudgeState.ActiveOn; } else { break; } if (HasStateTicks) { nextStateTick = NextStateTick; } else { break; } } } break; case JudgeState.ActiveOn: case JudgeState.ActiveOff: { var segmentCheck = m_currentStateTick.SegmentEntity; while (segmentCheck != null && segmentCheck.AbsoluteEndPosition < position && segmentCheck.NextConnected is AnalogEntity next) { segmentCheck = next; } m_desiredCursorPosition = segmentCheck.SampleValue(position); if (m_direction != 0) { m_lockTimer -= timeDelta * m_lockTimerSpeed; } if (m_lockTimer < 0) { m_lockTimer = 0; } if (AutoPlay) { CursorPosition = m_desiredCursorPosition; } var nextStateTick = NextStateTick; while (position - (nextStateTick.Position + JudgementOffset) >= 0) { if (nextStateTick.State == JudgeState.LaserEnd) { AdvanceStateTick(); OnHideCursor?.Invoke(); if (AutoPlay) { CursorPosition = m_desiredCursorPosition = nextStateTick.SegmentEntity.FinalValue; } m_state = JudgeState.Idle; m_currentStateTick = null; } else if (nextStateTick.State == JudgeState.SwitchDirection) { if (position > (nextStateTick.Position + JudgementOffset)) { if (position - (nextStateTick.Position + JudgementOffset) >= m_directionChangeRadius) { AdvanceStateTick(); m_direction = nextStateTick.SegmentEntity.DirectionSign; m_currentStateTick = nextStateTick; //Logger.Log($"Direction Switch ({ (m_direction == 1 ? "->" : (m_direction == -1 ? "<-" : "|")) }) Missed (by { position - (nextStateTick.Position + JudgementOffset) }): { nextStateTick.SegmentEntity.Position } ({ nextStateTick.SegmentEntity.AbsolutePosition })"); m_lockTimer = 0.0; } else { m_canControlCursorMovement = false; //Logger.Log($"Prevented automatic cursor moving while locked: direction switch origin passed without being played ({ nextStateTick.SegmentEntity.Position })"); break; } } } else if (nextStateTick.State == JudgeState.SameDirectionSlam && position - (nextStateTick.Position + JudgementOffset) >= m_directionChangeRadius) { AdvanceStateTick(); } else { break; } if (HasStateTicks) { nextStateTick = NextStateTick; } else { break; } } if (IsLocked && m_canControlCursorMovement) { CursorPosition = m_desiredCursorPosition; } IsBeingPlayed = IsLocked || MathL.Abs(m_desiredCursorPosition - CursorPosition) <= m_cursorActiveRange; if (IsBeingPlayed && m_direction == 0) { m_lockTimer = m_lockDuration; // NOTE(local): don't SetLocked, keep the timer decay speed if (m_canControlCursorMovement) { CursorPosition = m_desiredCursorPosition; } } if (HasScoreTicks) { var nextScoreTick = NextScoreTick; if (position - (nextScoreTick.Position + JudgementOffset) >= 0) { var resultKind = IsBeingPlayed ? JudgeKind.Passive : JudgeKind.Miss; OnTickProcessed?.Invoke(nextScoreTick.Entity, nextScoreTick.Position, new JudgeResult(0, resultKind)); AdvanceScoreTick(); } } } break; } if (HasStateTicks && position - (NextStateTick.Position + JudgementOffset) >= 0) { //Logger.Log($"{ NextStateTick.State } :: { NextStateTick.SegmentEntity.Position } or { NextStateTick.Position }"); } }
public void UserInput(float amount, time_t position) { if (!HasStateTicks && !HasScoreTicks) { return; } if (m_state == JudgeState.Idle) { return; } int inputDir = MathL.Sign(amount); if (HasStateTicks) { var nextStateTick = NextStateTick; if (nextStateTick.State == JudgeState.SwitchDirection) { time_t radius = MathL.Abs((double)(position - (NextStateTick.Position + JudgementOffset))); if (radius < m_directionChangeRadius && (inputDir == nextStateTick.SegmentEntity.DirectionSign || nextStateTick.SegmentEntity.DirectionSign == 0)) { if (m_lockTimer > 0.0 || IsBeingPlayed) { AdvanceStateTick(); m_direction = nextStateTick.SegmentEntity.DirectionSign; m_currentStateTick = nextStateTick; //Logger.Log($"Direction Switch ({ (m_direction == 1 ? "->" : (m_direction == -1 ? "<-" : "|")) }) Hit: { nextStateTick.SegmentEntity.Position } ({ nextStateTick.SegmentEntity.AbsolutePosition })"); if (nextStateTick.IsSlam) { OnSlamHit?.Invoke(position, nextStateTick.SegmentEntity); //Logger.Log($" Direction Switch on Slam: { CursorPosition }, { nextStateTick.SegmentEntity.InitialValue } ({ MathL.Abs(CursorPosition - nextStateTick.SegmentEntity.InitialValue) } <? { m_cursorActiveRange })"); // If the cursor was near the head of the laser, we lock it regardless of previous locked status. if (MathL.Abs(CursorPosition - nextStateTick.SegmentEntity.InitialValue) < m_cursorActiveRange) { //Logger.Log($" Direction Switch on Slam triggered Lock"); SetLocked(); } } else if (IsLocked) { SetLocked(); } } } } else if (nextStateTick.State == JudgeState.SameDirectionSlam) { time_t radius = MathL.Abs((double)(position - (NextStateTick.Position + JudgementOffset))); if (radius < m_directionChangeRadius && inputDir == m_direction) { Debug.Assert(nextStateTick.SegmentEntity.IsInstant); AdvanceStateTick(); OnSlamHit?.Invoke(position, nextStateTick.SegmentEntity); } } } if (IsLocked) { if (inputDir == m_direction) { SetLocked(); } else { m_lockTimerSpeed = 2.5; } } else { if (m_direction == 0) { // If we input at all, that's an active role by the user. // If the user inputs and the cursor happens to be really close, just consider it good! // They shouldn't need to pay so close attention to the cursor, this value can be tweaked // so that a wider radius is accepted. if (MathL.Abs(m_desiredCursorPosition - CursorPosition) < m_cursorActiveRange * 0.1f) { SetLocked(); } else if (CursorPosition < m_desiredCursorPosition) { if (inputDir == 1) { CursorPosition = MathL.Min(CursorPosition + amount, m_desiredCursorPosition); if (CursorPosition == m_desiredCursorPosition) { SetLocked(); } } else { CursorPosition = MathL.Max(0, CursorPosition + amount); } } else if (CursorPosition > m_desiredCursorPosition) { if (inputDir == -1) { CursorPosition = MathL.Max(CursorPosition + amount, m_desiredCursorPosition); if (CursorPosition == m_desiredCursorPosition) { SetLocked(); } } else { CursorPosition = MathL.Min(1, CursorPosition + amount); } } } else { // Same as above for non-directional lasers, if the player is actively // trying to play in the correct direction and the cursor happens to be in about // the right location we let them lock and keep going. if (inputDir == m_direction && MathL.Abs(m_desiredCursorPosition - CursorPosition) < m_cursorActiveRange * 0.1f) { SetLocked(); } else if (m_direction == 1) { if (inputDir == 1) { if (CursorPosition < m_desiredCursorPosition) { CursorPosition = MathL.Min(CursorPosition + amount, m_desiredCursorPosition); } else if (CursorPosition > m_desiredCursorPosition) { CursorPosition = MathL.Min(1, CursorPosition + amount); } if (CursorPosition == m_desiredCursorPosition) { SetLocked(); } } else { CursorPosition = MathL.Max(0, CursorPosition + amount); } } else if (m_direction == -1) { if (inputDir == -1) { if (CursorPosition > m_desiredCursorPosition) { CursorPosition = MathL.Max(CursorPosition + amount, m_desiredCursorPosition); } else if (CursorPosition < m_desiredCursorPosition) { CursorPosition = MathL.Max(0, CursorPosition + amount); } if (CursorPosition == m_desiredCursorPosition) { SetLocked(); } } else { CursorPosition = MathL.Min(1, CursorPosition + amount); } } } } }