/// <summary> /// Call at the point of judgement. Will switch stream to new difficulty as soon as possible (next new combo). /// </summary> /// <param name="newDifficulty">The new stream difficulty.</param> /// <returns>The time at which the switch will take place. -1 on failure.</returns> public virtual int SetActiveStream(Difficulty newDifficulty, bool instant = false) { Difficulty oldActiveStream = ActiveStream; if (ActiveStream == newDifficulty || (Clock.AudioTime > 0 && Clock.AudioTime < nextStreamChange)) { return(-1); //already switching stream } pList <HitObject> oldStreamObjects = ActiveStreamObjects; if (oldActiveStream == Difficulty.None || instant) { //loading a new stream. ActiveStream = newDifficulty; ProcessFrom = 0; ProcessTo = -1; return(0); } if (StreamHitObjects[(int)newDifficulty] == null) { return(-1); //no difficulty is mapped for the target stream. } int switchTime = Clock.AudioTime + DifficultyManager.PreEmpt; if (oldStreamObjects != null) { if (nextPossibleSwitchTime < switchTime) { //need to find a new switch time. removeBeforeObjectIndex = 0; if (beatmap.StreamSwitchPoints != null) { bool foundPoint = false; int c = beatmap.StreamSwitchPoints.Count; for (int i = 0; i < c; i++) { if (beatmap.StreamSwitchPoints[i] > switchTime) { switchTime = beatmap.StreamSwitchPoints[i]; foundPoint = true; break; } } if (!foundPoint) { //exhausted all stream switch points. nextPossibleSwitchTime = int.MaxValue; return(-1); } } //find a good point to stream switch. this will be mapper set later. for (int i = ProcessFrom; i < oldStreamObjects.Count; i++) { if (oldStreamObjects[i].NewCombo && oldStreamObjects[i].StartTime > switchTime) { removeBeforeObjectIndex = i; switchTime = i > 0 ? oldStreamObjects[i - 1].EndTime : oldStreamObjects[i].StartTime; break; } } nextPossibleSwitchTime = switchTime; } if (removeBeforeObjectIndex == 0) { //failed to find a suitable stream switch point. nextPossibleSwitchTime = int.MaxValue; return(-1); } switchTime = nextPossibleSwitchTime; int judgementStart = (int)(switchTime - Player.Beatmap.beatLengthAt(Clock.AudioTime) * 8); //check we are close enough to the switch time to actually judge this if (newDifficulty > oldActiveStream && Clock.AudioTime < judgementStart) { #if FULL_DEBUG DebugOverlay.AddLine("Waiting for next judgement section starting at " + judgementStart + "..."); #endif return(-1); } nextPossibleSwitchTime = 0; ActiveStream = newDifficulty; pList <HitObject> newStreamObjects = ActiveStreamObjects; SpriteManager newSpriteManager = ActiveStreamSpriteManager; for (int i = ProcessFrom; i < removeBeforeObjectIndex; i++) { newSpriteManager.Add(oldStreamObjects[i]); } if (removeBeforeObjectIndex - ProcessFrom > 0) { int removeBeforeIndex = 0; for (int i = 0; i < newStreamObjects.Count; i++) { HitObject h = newStreamObjects[i]; if (h.StartTime > switchTime && h.NewCombo) { removeBeforeIndex = i; break; } h.Sprites.ForEach(s => { s.Transformations.Clear(); s.Alpha = 0; }); h.Dispose(); } newStreamObjects.RemoveRange(0, removeBeforeIndex); newStreamObjects.InsertRange(0, oldStreamObjects.GetRange(ProcessFrom, removeBeforeObjectIndex - ProcessFrom)); } } ProcessFrom = 0; ProcessTo = -1; nextStreamChange = switchTime; return(switchTime); }