Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #region Gap Handling
- /// <summary>
- /// Called when a gap gate is successfully passed through. Typically called by the gate itself.
- /// </summary>
- /// <param name="performingBoard">the board that went through the gate</param>
- /// <param name="theGapGate">the gate they went through</param>
- static public void GapGatePassed(ISkateboardGateway performingBoard, GapGateZone theGapGate)
- {
- if (singleton == null) { return; }
- SkateboardGapTracker ourTracker = null;
- if (!singleton.completedGapLog.TryGetValue(performingBoard, out ourTracker))
- {
- ourTracker = new SkateboardGapTracker();
- singleton.completedGapLog.Add(performingBoard, ourTracker);
- }
- ourTracker.Log(theGapGate, performingBoard);
- }
- protected void EvaluateGaps()
- {
- // We iterate over the gap logs first, because if we ever optimize this, the simplest to optimize is the defined gaps (with a Dictionary), whereas this will always be an in-order iteration
- foreach (KeyValuePair<ISkateboardGateway, SkateboardGapTracker> skateboardGaps in completedGapLog)
- {
- LinkedListNode<CompletedGapGate> tempNode = skateboardGaps.Value.gapGateLog.First;
- while (tempNode != null)
- {
- // Now, check this against the first entry in each defined gap gate sequence
- // @TODO: If anyone ever wants to optimize this, you'd do it by stuffing the sequences into a Lookup class keyed on their first gate, probably up in Awake(), buuuut I'm too lazy for that
- for (int index = 0; index < namedGaps.Length; index++)
- {
- GapGateSequence namedGap = namedGaps[index];
- if (namedGap.gates == null) { continue; } // (REALLY? fuck it, let's error check, but... REALLY?!)
- bool sequenceCompleted = CheckGap(tempNode, namedGap);
- if (!sequenceCompleted && namedGap.bothWays) { sequenceCompleted = CheckGap(tempNode, namedGap, reverseOrder:true); }
- // If we get this far and it's positive? YAY! We did a gap!
- if (sequenceCompleted)
- {
- // @FIXME: This is where the better handling will go later, but we're gonna do a quickie test for now
- Debug.Log("Gap completed: " + namedGap.gapNameLocID);
- // Since we've just completed a gap, let's trigger a safety purge of this skateboard's logged gaps
- tempNode = null;
- break;
- }
- }
- if (tempNode != null) { tempNode = tempNode.Next; }
- else
- {
- // This means we found a valid gap, and should purge this skateboard's gap log to avoid repeat-detection
- skateboardGaps.Value.gapGateLog.Clear();
- // (and then we'll still be null on tempNode and thus drop nicely out of this on next loop)
- }
- }
- }
- }
- protected bool CheckGap(LinkedListNode<CompletedGapGate> loggedGateNode, GapGateSequence gapSequence, bool reverseOrder = false)
- {
- // First, figure out which way we're evaluating this gap
- int gateSeqIndex = 0;
- int gateSeqStep = 1;
- if (reverseOrder)
- {
- gateSeqIndex = gapSequence.gates.Length - 1;
- gateSeqStep = -1;
- }
- // Then just step through the sequence
- float lastGateTime = -1f;
- float gateTimeAccum = 0f;
- float lastGroundedTime = -1f;
- float groundedTimeAccum = 0f;
- bool sequenceCompleted = true;
- LinkedListNode<CompletedGapGate> tempComparisonNode = loggedGateNode;
- while (gateSeqIndex < gapSequence.gates.Length && gateSeqIndex >= 0)
- {
- // If we run out of logged gap gates before we run out of gates in the sequence, I guess we haven't hit the gap yet
- if (tempComparisonNode == null)
- {
- sequenceCompleted = false;
- break;
- }
- // Step through our logged gates until we find one that matches the next in the gate sequence - or we run out of gates
- while (tempComparisonNode != null && tempComparisonNode.Value.theGapGate != gapSequence.gates[gateSeqIndex])
- {
- // When we start skipping nodes that don't match, it means we need to reset our sequence check to the first one in the sequence again
- gateSeqIndex = reverseOrder ? gapSequence.gates.Length - 1 : 0;
- gateTimeAccum = groundedTimeAccum = 0f;
- lastGateTime = lastGroundedTime = -1f;
- // (this lets us handle cases where gap detections overlap, and there's a totally unrelated gap gate in the space between the two gates that define the gap we're testing for)
- tempComparisonNode = tempComparisonNode.Next;
- // (the fall-through case here wraps around and catches the null check above and falses us out, easy peasy)
- }
- // Assuming we still have a node / we found a node...
- if (tempComparisonNode != null)
- {
- // Handle accumulation of properties between states
- if (lastGateTime >= 0f) { gateTimeAccum += Mathf.Max(tempComparisonNode.Value.timeGapCompleted - lastGateTime, 0f); }
- lastGateTime = tempComparisonNode.Value.timeGapCompleted;
- if (lastGroundedTime >= 0f) { groundedTimeAccum += Mathf.Max(tempComparisonNode.Value.groundedTime - lastGroundedTime, 0f); }
- lastGroundedTime = tempComparisonNode.Value.groundedTime;
- // Neeext
- tempComparisonNode = tempComparisonNode.Next;
- }
- gateSeqIndex += gateSeqStep;
- // If we go past one of our (assigned to something valid) limiters, that's it, the gap doesn't count anyways
- if (gapSequence.maxGrounded > 0f && groundedTimeAccum > gapSequence.maxGrounded)
- {
- sequenceCompleted = false;
- break;
- }
- if (gapSequence.timeLimit > 0f && groundedTimeAccum > gapSequence.timeLimit)
- {
- sequenceCompleted = false;
- break;
- }
- }
- return sequenceCompleted;
- }
- /// <summary>
- /// Sweeps through the gap gate logs and removes entries too old to matter anymore
- /// </summary>
- protected void PruneGapGateLogs()
- {
- foreach(KeyValuePair<ISkateboardGateway, SkateboardGapTracker> skateboardGaps in completedGapLog)
- {
- LinkedListNode<CompletedGapGate> headNode = skateboardGaps.Value.gapGateLog.First;
- while(headNode != null && Time.timeSinceLevelLoad - headNode.Value.timeGapCompleted >= GapCompletionTimeout)
- {
- skateboardGaps.Value.gapGateLog.RemoveFirst();
- headNode = skateboardGaps.Value.gapGateLog.First;
- }
- }
- }
- protected class SkateboardGapTracker
- {
- public LinkedList<CompletedGapGate> gapGateLog = new LinkedList<CompletedGapGate>();
- public CompletedGapGate Log(GapGateZone theGapGate, ISkateboardGateway performingBoard)
- {
- CompletedGapGate newGapGate = null;
- // First, check the very last node. If it's for this gap gate (ie. a repeat trigger), we just update it
- LinkedListNode<CompletedGapGate> logNode = gapGateLog.Last;
- if (logNode != null && logNode.Value.theGapGate == theGapGate)
- {
- newGapGate = logNode.Value;
- }
- // Otherwise, we create a new one and add it to the end
- else
- {
- newGapGate = new CompletedGapGate();
- gapGateLog.AddLast(newGapGate);
- }
- // Either way, update/set the args, and we're done!
- newGapGate.theGapGate = theGapGate;
- newGapGate.timeGapCompleted = Time.timeSinceLevelLoad;
- newGapGate.groundedTime = performingBoard.Movement.TotalTimeGrounded;
- return newGapGate;
- }
- }
- protected class CompletedGapGate
- {
- public GapGateZone theGapGate;
- public float timeGapCompleted = -1f;
- public float groundedTime = -1f;
- }
- [System.Serializable]
- protected class GapGateSequence
- {
- public string gapNameLocID;
- public float score;
- public bool bothWays = true;
- public float timeLimit = -1f;
- public float maxGrounded = -1f;
- public GapGateZone[] gates;
- }
- #endregion
- #region Console Command Defs
- [ConsoleCommand]
- static protected string SkipMission()
- {
- singleton.skipThisMission = true;
- return "Skipping current mission";
- }
- #endregion
Advertisement
Add Comment
Please, Sign In to add comment