Guest User

Untitled

a guest
Nov 6th, 2020
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.72 KB | None | 0 0
  1. #region Gap Handling
  2. /// <summary>
  3. /// Gets the localized name of the gap
  4. /// </summary>
  5. /// <param name="gapName">the gap you want the name for</param>
  6. /// <returns>the localized name of the gap (or null if invalid)</returns>
  7. static public string GetLocalizedGapName(string gapName)
  8. {
  9. if (string.IsNullOrEmpty(gapName)) { return null; }
  10.  
  11. string locID = GapLocPrefix + gapName.ToLowerInvariant();
  12.  
  13. string localizedName = LocalizationManager.GetTranslation(locID);
  14. if (string.IsNullOrEmpty(localizedName))
  15. {
  16. localizedName = gapName + " ::LOCALIZE:" + locID;
  17. Debug.Log("Gap loc missing, locID: " + locID);
  18. }
  19.  
  20. return localizedName;
  21. }
  22.  
  23. /// <summary>
  24. /// Called when a gap gate is successfully passed through. Typically called by the gate itself.
  25. /// </summary>
  26. /// <param name="performingBoard">the board that went through the gate</param>
  27. /// <param name="theGapGate">the gate they went through</param>
  28. static public void GapGatePassed(ISkateboardGateway performingBoard, GapGateZone theGapGate)
  29. {
  30. if (singleton == null) { return; }
  31.  
  32. SkateboardGapTracker ourTracker = null;
  33. if (!singleton.completedGapLog.TryGetValue(performingBoard, out ourTracker))
  34. {
  35. ourTracker = new SkateboardGapTracker();
  36.  
  37. singleton.completedGapLog.Add(performingBoard, ourTracker);
  38. }
  39.  
  40. ourTracker.Log(theGapGate, performingBoard);
  41. }
  42.  
  43. protected void EvaluateGaps()
  44. {
  45. // 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
  46. foreach (KeyValuePair<ISkateboardGateway, SkateboardGapTracker> skateboardGaps in completedGapLog)
  47. {
  48. LinkedListNode<CompletedGapGate> tempNode = skateboardGaps.Value.gapGateLog.First;
  49. while (tempNode != null)
  50. {
  51. // Now, check this against the first entry in each defined gap gate sequence
  52. // @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
  53. for (int index = 0; index < namedGaps.Length; index++)
  54. {
  55. GapGateSequence namedGap = namedGaps[index];
  56. if (namedGap.gates == null) { continue; } // (REALLY? fuck it, let's error check, but... REALLY?!)
  57.  
  58. bool sequenceCompleted = CheckGap(tempNode, namedGap);
  59. if (!sequenceCompleted && namedGap.bothWays) { sequenceCompleted = CheckGap(tempNode, namedGap, reverseOrder: true); }
  60.  
  61. // If we get this far and it's positive? YAY! We did a gap!
  62. if (sequenceCompleted)
  63. {
  64. skateboardGaps.Key.Combo.AddGap(namedGaps[index]);
  65.  
  66. // Since we've just completed a gap, let's trigger a safety purge of this skateboard's logged gaps
  67. tempNode = null;
  68. break;
  69. }
  70. }
  71.  
  72. if (tempNode != null) { tempNode = tempNode.Next; }
  73. else
  74. {
  75. // This means we found a valid gap, and should purge this skateboard's gap log to avoid repeat-detection
  76. skateboardGaps.Value.gapGateLog.Clear();
  77.  
  78. // (and then we'll still be null on tempNode and thus drop nicely out of this on next loop)
  79. }
  80. }
  81. }
  82. }
  83.  
  84. protected bool CheckGap(LinkedListNode<CompletedGapGate> loggedGateNode, GapGateSequence gapSequence, bool reverseOrder = false)
  85. {
  86. // First, figure out which way we're evaluating this gap
  87. int gateSeqIndex = 0;
  88. int gateSeqStep = 1;
  89.  
  90. if (reverseOrder)
  91. {
  92. gateSeqIndex = gapSequence.gates.Length - 1;
  93. gateSeqStep = -1;
  94. }
  95.  
  96. // Then just step through the sequence
  97. float lastGateTime = -1f;
  98. float gateTimeAccum = 0f;
  99. float lastGroundedTime = -1f;
  100. float groundedTimeAccum = 0f;
  101. bool sequenceCompleted = true;
  102. LinkedListNode<CompletedGapGate> tempComparisonNode = loggedGateNode;
  103. while (gateSeqIndex < gapSequence.gates.Length && gateSeqIndex >= 0)
  104. {
  105. // 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
  106. if (tempComparisonNode == null)
  107. {
  108. sequenceCompleted = false;
  109. break;
  110. }
  111.  
  112. // Step through our logged gates until we find one that matches the next in the gate sequence - or we run out of gates
  113. while (tempComparisonNode != null && tempComparisonNode.Value.theGapGate != gapSequence.gates[gateSeqIndex])
  114. {
  115. // 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
  116. gateSeqIndex = reverseOrder ? gapSequence.gates.Length - 1 : 0;
  117. gateTimeAccum = groundedTimeAccum = 0f;
  118. lastGateTime = lastGroundedTime = -1f;
  119.  
  120. // (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)
  121. tempComparisonNode = tempComparisonNode.Next;
  122.  
  123. // (the fall-through case here wraps around and catches the null check above and falses us out, easy peasy)
  124. }
  125.  
  126. // Assuming we still have a node / we found a node...
  127. if (tempComparisonNode != null)
  128. {
  129. // Handle accumulation of properties between states
  130. if (lastGateTime >= 0f) { gateTimeAccum += Mathf.Max(tempComparisonNode.Value.timeGapCompleted - lastGateTime, 0f); }
  131. lastGateTime = tempComparisonNode.Value.timeGapCompleted;
  132.  
  133. if (lastGroundedTime >= 0f) { groundedTimeAccum += Mathf.Max(tempComparisonNode.Value.groundedTime - lastGroundedTime, 0f); }
  134. lastGroundedTime = tempComparisonNode.Value.groundedTime;
  135.  
  136. // Neeext
  137. tempComparisonNode = tempComparisonNode.Next;
  138. }
  139. gateSeqIndex += gateSeqStep;
  140.  
  141. // If we go past one of our (assigned to something valid) limiters, that's it, the gap doesn't count anyways
  142. if (gapSequence.maxGrounded > 0f && groundedTimeAccum > gapSequence.maxGrounded)
  143. {
  144. sequenceCompleted = false;
  145. break;
  146. }
  147.  
  148. if (gapSequence.timeLimit > 0f && groundedTimeAccum > gapSequence.timeLimit)
  149. {
  150. sequenceCompleted = false;
  151. break;
  152. }
  153. }
  154.  
  155. return sequenceCompleted;
  156. }
  157.  
  158. /// <summary>
  159. /// Sweeps through the gap gate logs and removes entries too old to matter anymore
  160. /// </summary>
  161. protected void PruneGapGateLogs()
  162. {
  163. foreach (KeyValuePair<ISkateboardGateway, SkateboardGapTracker> skateboardGaps in completedGapLog)
  164. {
  165. LinkedListNode<CompletedGapGate> headNode = skateboardGaps.Value.gapGateLog.First;
  166. while (headNode != null && Time.timeSinceLevelLoad - headNode.Value.timeGapCompleted >= GapCompletionTimeout)
  167. {
  168. skateboardGaps.Value.gapGateLog.RemoveFirst();
  169. headNode = skateboardGaps.Value.gapGateLog.First;
  170. }
  171. }
  172. }
  173.  
  174. protected class SkateboardGapTracker
  175. {
  176. public LinkedList<CompletedGapGate> gapGateLog = new LinkedList<CompletedGapGate>();
  177.  
  178. public CompletedGapGate Log(GapGateZone theGapGate, ISkateboardGateway performingBoard)
  179. {
  180. CompletedGapGate newGapGate = null;
  181.  
  182. // First, check the very last node. If it's for this gap gate (ie. a repeat trigger), we just update it
  183. LinkedListNode<CompletedGapGate> logNode = gapGateLog.Last;
  184. if (logNode != null && logNode.Value.theGapGate == theGapGate)
  185. {
  186. newGapGate = logNode.Value;
  187. }
  188. // Otherwise, we create a new one and add it to the end
  189. else
  190. {
  191. newGapGate = new CompletedGapGate();
  192. gapGateLog.AddLast(newGapGate);
  193. }
  194.  
  195. // Either way, update/set the args, and we're done!
  196. newGapGate.theGapGate = theGapGate;
  197. newGapGate.timeGapCompleted = Time.timeSinceLevelLoad;
  198. newGapGate.groundedTime = performingBoard.Movement.TotalTimeGrounded;
  199.  
  200. return newGapGate;
  201. }
  202. }
  203.  
  204. protected class CompletedGapGate
  205. {
  206. public GapGateZone theGapGate;
  207. public float timeGapCompleted = -1f;
  208. public float groundedTime = -1f;
  209. }
  210.  
  211. [System.Serializable]
  212. public class GapGateSequence
  213. {
  214. public string gapName;
  215. public int score;
  216. public bool bothWays = true;
  217. public float timeLimit = -1f;
  218. public float maxGrounded = -1f;
  219. public GapGateZone[] gates;
  220. }
Add Comment
Please, Sign In to add comment