package com.fteams.siftrain.util.random; import com.badlogic.gdx.utils.Array; import com.fteams.siftrain.assets.GlobalConfiguration; import com.fteams.siftrain.objects.CircleMark; import com.fteams.siftrain.util.SongUtils; public class NewAlgorithmRandomizer extends Randomizer { private boolean left; private boolean holding; private double holdEndTime; // 5 ms of buffer to prevent simultaneous notes on the same side /* * Info: by default beatmaps will use 2 notes at the same time at most. If there's more, things can get nasty and messy. */ public void randomize(Array<CircleMark> marks) { marks.sort(); double threshold = SongUtils.getDefaultNoteSpeedForApproachRate(GlobalConfiguration.noteSpeed) / 4.0; holding = false; // set the position for each note for (int i = 0; i < marks.size; i++) { CircleMark mark = marks.get(i); if (mark.getNote().timing_sec > holdEndTime) { holding = false; } boolean isLeft = Math.random() > 0.5; // this note is a hold if (mark.hold) { randomizeHold(marks, i, isLeft, threshold); } else // not a hold { randomizeNotHold(marks, i, isLeft, threshold); } } } private void randomizeHold(Array<CircleMark> marks, int i, boolean isLeft, double threshold) { CircleMark mark = marks.get(i); // we're holding! if (holding) { // note during hold which ends after the current end time // swap times. if (mark.getNote().timing_sec + mark.getNote().effect_value > holdEndTime) { holdEndTime = mark.getNote().timing_sec + mark.getNote().effect_value + BUFFER_TIME; left = !left; Integer pos = getPositionWithoutMiddle(left); mark.updateDestination(pos); mark.left = left; // new hold is shorter than the previous one // just add it. } else { isLeft = !left; Integer pos = getPositionWithoutMiddle(isLeft); mark.updateDestination(pos); mark.left = isLeft; } // we got a hold and we're not holding } else { holding = true; double previousHoldEndTime = holdEndTime; holdEndTime = mark.getNote().timing_sec + mark.getNote().effect_value + BUFFER_TIME; // check the previous note for side calculation - just in case if (i >= 1) { CircleMark previous = marks.get(i - 1); // we're no longer holding, but the new hold spawns close to the previous released hold if (mark.getNote().timing_sec - previousHoldEndTime < threshold) { left = !left; Integer pos = getPositionWithoutMiddle(left); mark.updateDestination(pos); mark.left = left; } // notes close together must go to different sides else if (mark.getNote().timing_sec - previous.getNote().timing_sec < threshold) { isLeft = !previous.left; Integer pos = getPositionWithoutMiddle(isLeft); mark.updateDestination(pos); mark.left = isLeft; left = isLeft; // if the new note is released really close to the last hold, make sure to release on the other side } else { isLeft = !left; Integer pos = getPositionWithoutMiddle(isLeft); mark.updateDestination(pos); mark.left = isLeft; left = isLeft; } // if the note is the first one, we just pick a random side and spawn it there. } else { left = isLeft; Integer pos = getPositionWithoutMiddle(left); mark.updateDestination(pos); mark.left = isLeft; left = isLeft; } } } private void randomizeNotHold(Array<CircleMark> marks, int i, boolean isLeft, double threshold) { CircleMark mark = marks.get(i); // we're holding if (holding) { // pick the other side isLeft = !left; // if one side is holding, notes will never spawn in the middle lane Integer pos = getPositionWithoutMiddle(isLeft, mark.getNote().timing_sec); mark.updateDestination(pos); mark.left = isLeft; // we're not holding } else { // and this is not the first note if (i >= 1) { CircleMark previous = marks.get(i - 1); // if the notes are close together, use different sides if (mark.getNote().timing_sec - previous.getNote().timing_sec < threshold) { isLeft = !previous.left; // if notes are too close together, we don't pick up the center // this also applies to simultaneous notes (distance will obviously be < average) Integer pos = getPositionWithoutMiddle(isLeft, mark.getNote().timing_sec); mark.updateDestination(pos); mark.left = isLeft; // we're not holding but there was a hold released close - swap sides } else if (mark.getNote().timing_sec - holdEndTime < threshold) { // they're far away and we may choose a side randomly isLeft = !left; Integer pos = getPositionWithoutMiddle(isLeft, mark.getNote().timing_sec); mark.updateDestination(pos); mark.left = isLeft; // if they're not really close, just pick a random side } else if (hasSimultEndBeforeCurrentNote(marks, i, i-1)) { isLeft = !left; Integer pos = getPositionWithoutMiddle(isLeft, mark.getNote().timing_sec); mark.updateDestination(pos); mark.left = isLeft; } else { Integer pos = getPosition(isLeft); // if the note is multi - don't pick the center if ((mark.effect & (SongUtils.NOTE_TYPE_SIMULT_END | SongUtils.NOTE_TYPE_SIMULT_START)) != 0) { pos = getPositionWithoutMiddle(isLeft, mark.getNote().timing_sec); } mark.updateDestination(pos); mark.left = isLeft; } // if this is the first note, just pick a random side } else { Integer pos = getPosition(isLeft, mark.getNote().timing_sec); // if the first note is a simult, choose a random side - no center if ((mark.effect & (SongUtils.NOTE_TYPE_SIMULT_START | SongUtils.NOTE_TYPE_SIMULT_END)) != 0) { pos = getPositionWithoutMiddle(isLeft, mark.getNote().timing_sec); } mark.updateDestination(pos); mark.left = isLeft; } } } public Integer getPosition(boolean isLeft, Double timing) { Integer newPosition = getPosition(isLeft); // try to get a spot on one side if (hasSpots(isLeft, timing)) { while (inUse(newPosition, timing)) { newPosition = getPosition(isLeft); } } else // if we couldn't get a spot because all are on cooldown, use a spot from the other side { if (hasSpots(!isLeft, timing)){ while (inUse(newPosition, timing)) { newPosition = getPosition(!isLeft); } } // if the spots are all in use, use the center. else { newPosition = 4; } } noteToReleaseTime.put(newPosition, timing + BUFFER_TIME); return newPosition; } public Integer getPositionWithoutMiddle(boolean isLeft, Double timing) { Integer newPosition = getPositionWithoutMiddle(isLeft); if (hasSpots(isLeft, timing)) { while (inUse(newPosition, timing)) { newPosition = getPositionWithoutMiddle(isLeft); } } else { if (hasSpots(!isLeft, timing)){ while (inUse(newPosition, timing)) { newPosition = getPositionWithoutMiddle(!isLeft); } } else { newPosition = 5; } } noteToReleaseTime.put(newPosition, timing + BUFFER_TIME); return newPosition; } }