Files
FNF-i486-Engine/source/Conductor.hx
Moxie 990bbc588c fixed videos crashing (finally)
it was a missing library, the whole time
2025-01-01 23:25:36 -05:00

236 lines
6.1 KiB
Haxe

package;
import Song.SwagSong;
typedef BPMChangeEvent =
{
var stepTime:Int;
var songTime:Float;
var bpm:Float;
@:optional var stepCrochet:Float;
}
class Conductor
{
public static var bpm:Float = 100;
public static var crochet:Float = ((60 / bpm) * 1000); // beats in milliseconds
public static var stepCrochet:Float = crochet / 4; // steps in milliseconds
public static var songPosition:Float=0;
public static var offset:Float = 0;
//public static var safeFrames:Int = 10;
// credits to duskiewhy for making this
public static var safeZoneOffset:Float = (ClientPrefs.safeFrames / 60) * 1000; // is calculated in create(), is safeFrames in milliseconds
public static var timeScale:Float = Conductor.safeZoneOffset / 180; //max hit window should be 180 right?
public static var ROWS_PER_BEAT = 48; // from Stepmania
public static var BEATS_PER_MEASURE = 4; // TODO: time sigs
public static var ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE; // from Stepmania
public static var MAX_NOTE_ROW = 1 << 30; // from Stepmania
public inline static function beatToRow(beat:Float):Int
return Math.round(beat * ROWS_PER_BEAT);
public inline static function rowToBeat(row:Int):Float
return row / ROWS_PER_BEAT;
public inline static function secsToRow(sex:Float):Int
return Math.round(getBeat(sex) * ROWS_PER_BEAT);
public static var bpmChangeMap:Array<BPMChangeEvent> = [];
public function new()
{
}
public static function recalculateTimings()
{
Conductor.safeZoneOffset = Math.floor((ClientPrefs.safeFrames / 60) * 1000);
Conductor.timeScale = Conductor.safeZoneOffset / 180;
}
public static function judgeNote(note:Note, diff:Float=0, ?botplay:Bool = false, ?missedNote:Bool = false):Rating // die
{
if (botplay || missedNote) return PlayState.instance.ratingsData[0];
var data:Array<Rating> = PlayState.instance.ratingsData; //shortening cuz fuck u
for(i in 0...data.length-1) //skips last window (Shit)
{
if (diff <= data[i].hitWindow)
{
return data[i];
}
}
return data[data.length - 1];
}
public static function getCrotchetAtTime(time:Float){
var lastChange = getBPMFromSeconds(time);
return lastChange.stepCrochet*4;
}
public static function getBPMFromSeconds(time:Float){
var lastChange:BPMChangeEvent = {
stepTime: 0,
songTime: 0,
bpm: bpm,
stepCrochet: stepCrochet
}
for (i in 0...Conductor.bpmChangeMap.length)
{
if (time >= Conductor.bpmChangeMap[i].songTime)
lastChange = Conductor.bpmChangeMap[i];
}
return lastChange;
}
public static function getBPMFromStep(step:Float){
var lastChange:BPMChangeEvent = {
stepTime: 0,
songTime: 0,
bpm: bpm,
stepCrochet: stepCrochet
}
for (i in 0...Conductor.bpmChangeMap.length)
{
if (Conductor.bpmChangeMap[i].stepTime<=step)
lastChange = Conductor.bpmChangeMap[i];
}
return lastChange;
}
public static function beatToSeconds(beat:Float): Float{
var step = beat * 4;
var lastChange = getBPMFromStep(step);
return lastChange.songTime + ((step - lastChange.stepTime) / (lastChange.bpm / 60)/4) * 1000; // TODO: make less shit and take BPM into account PROPERLY
}
public static function getStep(time:Float){
var lastChange = getBPMFromSeconds(time);
return lastChange.stepTime + (time - lastChange.songTime) / lastChange.stepCrochet;
}
public static function getStepRounded(time:Float){
var lastChange = getBPMFromSeconds(time);
return lastChange.stepTime + Math.floor(time - lastChange.songTime) / lastChange.stepCrochet;
}
public static function getBeat(time:Float){
return getStep(time)/4;
}
public static function getBeatRounded(time:Float):Int{
return Math.floor(getStepRounded(time)/4);
}
public static function mapBPMChanges(song:SwagSong)
{
bpmChangeMap = [];
var curBPM:Float = song.bpm;
var totalSteps:Int = 0;
var totalPos:Float = 0;
for (i in 0...song.notes.length)
{
if(song.notes[i].changeBPM && song.notes[i].bpm != curBPM)
{
curBPM = song.notes[i].bpm;
var event:BPMChangeEvent = {
stepTime: totalSteps,
songTime: totalPos,
bpm: curBPM,
stepCrochet: calculateCrochet(curBPM)/4
};
bpmChangeMap.push(event);
}
var deltaSteps:Int = Math.round(getSectionBeats(song, i) * 4);
totalSteps += deltaSteps;
totalPos += ((60 / curBPM) * 1000 / 4) * deltaSteps;
}
trace("new BPM map BUDDY " + bpmChangeMap);
}
static function getSectionBeats(song:SwagSong, section:Int)
{
var val:Null<Float> = null;
if(song.notes[section] != null) val = song.notes[section].sectionBeats;
return val != null ? val : 4;
}
inline public static function calculateCrochet(bpm:Float){
return (60/bpm)*1000;
}
public static function changeBPM(newBpm:Float)
{
bpm = newBpm;
crochet = calculateCrochet(bpm);
stepCrochet = crochet / 4;
}
}
class Rating
{
public var name:String = '';
public var image:String = '';
public var counter:String = '';
public var hitWindow:Null<Int> = 0; //ms
public var ratingMod:Float = 1;
public var score:Int = 500;
public var noteSplash:Bool = true;
public function new(name:String)
{
this.name = name;
this.image = name;
this.counter = name + 's';
this.hitWindow = Reflect.field(ClientPrefs, name + 'Window');
if(hitWindow == null)
{
hitWindow = 0;
}
}
public static function loadDefault():Array<Rating>
{
var ratingsData:Array<Rating> = [];
if (!ClientPrefs.noMarvJudge)
{
ratingsData.push(new Rating('perfect'));
}
var rating:Rating = new Rating('sick');
rating.ratingMod = 1;
rating.score = 350;
rating.noteSplash = true;
ratingsData.push(rating);
var rating:Rating = new Rating('good');
rating.ratingMod = 0.7;
rating.score = 200;
rating.noteSplash = false;
ratingsData.push(rating);
var rating:Rating = new Rating('bad');
rating.ratingMod = 0.4;
rating.score = 100;
rating.noteSplash = false;
ratingsData.push(rating);
var rating:Rating = new Rating('shit');
rating.ratingMod = 0;
rating.score = 50;
rating.noteSplash = false;
ratingsData.push(rating);
return ratingsData;
}
public function increase(blah:Int = 1)
{
Reflect.setField(PlayState.instance, counter, Reflect.field(PlayState.instance, counter) + blah);
}
}