mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-03-21 17:39:20 +00:00
WIP on conductor rework
This commit is contained in:
parent
7fbdbcdfad
commit
9ebb566b2a
|
@ -1,11 +1,10 @@
|
||||||
package funkin;
|
package funkin;
|
||||||
|
|
||||||
import funkin.SongLoad.SwagSong;
|
import funkin.SongLoad.SwagSong;
|
||||||
|
import funkin.play.song.Song.SongDifficulty;
|
||||||
|
import funkin.play.song.SongData.ConductorTimeChange;
|
||||||
|
import funkin.play.song.SongData.SongTimeChange;
|
||||||
|
|
||||||
/**
|
|
||||||
* ...
|
|
||||||
* @author
|
|
||||||
*/
|
|
||||||
typedef BPMChangeEvent =
|
typedef BPMChangeEvent =
|
||||||
{
|
{
|
||||||
var stepTime:Int;
|
var stepTime:Int;
|
||||||
|
@ -16,12 +15,40 @@ typedef BPMChangeEvent =
|
||||||
class Conductor
|
class Conductor
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Beats per minute of the song.
|
* The list of time changes in the song.
|
||||||
|
* There should be at least one time change (at the beginning of the song) to define the BPM.
|
||||||
*/
|
*/
|
||||||
public static var bpm:Float = 100;
|
private static var timeChanges:Array<ConductorTimeChange> = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Duration of a beat in millisecond.
|
* The current time change.
|
||||||
|
*/
|
||||||
|
private static var currentTimeChange:ConductorTimeChange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current position in the song in milliseconds.
|
||||||
|
* Updated every frame based on the audio position.
|
||||||
|
*/
|
||||||
|
public static var songPosition:Float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beats per minute of the current song at the current time.
|
||||||
|
*/
|
||||||
|
public static var bpm(get, null):Float = 100;
|
||||||
|
|
||||||
|
static function get_bpm():Float
|
||||||
|
{
|
||||||
|
if (currentTimeChange == null)
|
||||||
|
return 100;
|
||||||
|
|
||||||
|
return currentTimeChange.bpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OLD, replaced with timeChanges.
|
||||||
|
public static var bpmChangeMap:Array<BPMChangeEvent> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration of a beat in millisecond. Calculated based on bpm.
|
||||||
*/
|
*/
|
||||||
public static var crochet(get, null):Float;
|
public static var crochet(get, null):Float;
|
||||||
|
|
||||||
|
@ -31,7 +58,7 @@ class Conductor
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Duration of a step in milliseconds.
|
* Duration of a step in milliseconds. Calculated based on bpm.
|
||||||
*/
|
*/
|
||||||
public static var stepCrochet(get, null):Float;
|
public static var stepCrochet(get, null):Float;
|
||||||
|
|
||||||
|
@ -40,19 +67,62 @@ class Conductor
|
||||||
return crochet / 4;
|
return crochet / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static var currentBeat(get, null):Float;
|
||||||
* The current position in the song in milliseconds.
|
|
||||||
*/
|
static function get_currentBeat():Float
|
||||||
public static var songPosition:Float;
|
{
|
||||||
|
return currentBeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var currentStep(get, null):Int;
|
||||||
|
|
||||||
|
static function get_currentStep():Int
|
||||||
|
{
|
||||||
|
return currentStep;
|
||||||
|
}
|
||||||
|
|
||||||
public static var lastSongPos:Float;
|
public static var lastSongPos:Float;
|
||||||
public static var visualOffset:Float = 0;
|
public static var visualOffset:Float = 0;
|
||||||
public static var audioOffset:Float = 0;
|
public static var audioOffset:Float = 0;
|
||||||
public static var offset:Float = 0;
|
public static var offset:Float = 0;
|
||||||
|
|
||||||
public static var bpmChangeMap:Array<BPMChangeEvent> = [];
|
public function new()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public function new() {}
|
public static function getLastBPMChange()
|
||||||
|
{
|
||||||
|
var lastChange:BPMChangeEvent = {
|
||||||
|
stepTime: 0,
|
||||||
|
songTime: 0,
|
||||||
|
bpm: 0
|
||||||
|
}
|
||||||
|
for (i in 0...Conductor.bpmChangeMap.length)
|
||||||
|
{
|
||||||
|
if (Conductor.songPosition >= Conductor.bpmChangeMap[i].songTime)
|
||||||
|
lastChange = Conductor.bpmChangeMap[i];
|
||||||
|
|
||||||
|
if (Conductor.songPosition < Conductor.bpmChangeMap[i].songTime)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return lastChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function forceBPM(bpm:Float)
|
||||||
|
{
|
||||||
|
// TODO: Get rid of this and use song metadata instead.
|
||||||
|
Conductor.bpm = bpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the conductor with the current song position.
|
||||||
|
* BPM, current step, etc. will be re-calculated based on the song position.
|
||||||
|
*/
|
||||||
|
public static function update(songPosition:Float)
|
||||||
|
{
|
||||||
|
Conductor.songPosition = songPosition;
|
||||||
|
Conductor.bpm = Conductor.getLastBPMChange().bpm;
|
||||||
|
}
|
||||||
|
|
||||||
public static function mapBPMChanges(song:SwagSong)
|
public static function mapBPMChanges(song:SwagSong)
|
||||||
{
|
{
|
||||||
|
@ -80,4 +150,34 @@ class Conductor
|
||||||
}
|
}
|
||||||
trace("new BPM map BUDDY " + bpmChangeMap);
|
trace("new BPM map BUDDY " + bpmChangeMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function mapTimeChanges(currentChart:SongDifficulty)
|
||||||
|
{
|
||||||
|
var songTimeChanges:Array<SongTimeChange> = currentChart.timeChanges;
|
||||||
|
|
||||||
|
timeChanges = [];
|
||||||
|
|
||||||
|
for (songTimeChange in timeChanges)
|
||||||
|
{
|
||||||
|
var prevTimeChange:ConductorTimeChange = timeChanges.length == 0 ? null : timeChanges[timeChanges.length - 1];
|
||||||
|
var currentTimeChange:ConductorTimeChange = cast songTimeChange;
|
||||||
|
|
||||||
|
if (prevTimeChange != null)
|
||||||
|
{
|
||||||
|
var deltaTime:Float = currentTimeChange.timeStamp - prevTimeChange.timeStamp;
|
||||||
|
var deltaSteps:Int = Math.round(deltaTime / (60 / prevTimeChange.bpm) * 1000 / 4);
|
||||||
|
|
||||||
|
currentTimeChange.stepTime = prevTimeChange.stepTime + deltaSteps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We know the time and steps of this time change is 0, since this is the first time change.
|
||||||
|
currentTimeChange.stepTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeChanges.push(currentTimeChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import funkin.freeplayStuff.FreeplayScore;
|
||||||
import funkin.freeplayStuff.SongMenuItem;
|
import funkin.freeplayStuff.SongMenuItem;
|
||||||
import funkin.play.HealthIcon;
|
import funkin.play.HealthIcon;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
import funkin.shaderslmfao.AngleMask;
|
import funkin.shaderslmfao.AngleMask;
|
||||||
import funkin.shaderslmfao.PureColor;
|
import funkin.shaderslmfao.PureColor;
|
||||||
import funkin.shaderslmfao.StrokeShader;
|
import funkin.shaderslmfao.StrokeShader;
|
||||||
|
@ -97,7 +98,7 @@ class FreeplayState extends MusicBeatSubstate
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StoryMenuState.weekUnlocked[2] || isDebug)
|
if (StoryMenuState.weekUnlocked[2] || isDebug)
|
||||||
addWeek(['Bopeebo', 'Fresh', 'Dadbattle'], 1, ['dad']);
|
addWeek(['Bopeebo', 'Bopeebo_new', 'Fresh', 'Dadbattle'], 1, ['dad']);
|
||||||
|
|
||||||
if (StoryMenuState.weekUnlocked[2] || isDebug)
|
if (StoryMenuState.weekUnlocked[2] || isDebug)
|
||||||
addWeek(['Spookeez', 'South', 'Monster'], 2, ['spooky', 'spooky', 'monster']);
|
addWeek(['Spookeez', 'South', 'Monster'], 2, ['spooky', 'spooky', 'monster']);
|
||||||
|
@ -520,8 +521,10 @@ class FreeplayState extends MusicBeatSubstate
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
PlayState.currentSong = SongLoad.loadFromJson(poop, songs[curSelected].songName.toLowerCase());
|
PlayState.currentSong = SongLoad.loadFromJson(poop, songs[curSelected].songName.toLowerCase());
|
||||||
|
PlayState.currentSong_NEW = SongDataParser.fetchSong(songs[curSelected].songName.toLowerCase());
|
||||||
PlayState.isStoryMode = false;
|
PlayState.isStoryMode = false;
|
||||||
PlayState.storyDifficulty = curDifficulty;
|
PlayState.storyDifficulty = curDifficulty;
|
||||||
|
PlayState.storyDifficulty_NEW = 'easy';
|
||||||
// SongLoad.curDiff = Highscore.formatSong()
|
// SongLoad.curDiff = Highscore.formatSong()
|
||||||
|
|
||||||
SongLoad.curDiff = switch (curDifficulty)
|
SongLoad.curDiff = switch (curDifficulty)
|
||||||
|
@ -562,6 +565,7 @@ class FreeplayState extends MusicBeatSubstate
|
||||||
intendedScore = FlxG.random.int(0, 100000);
|
intendedScore = FlxG.random.int(0, 100000);
|
||||||
|
|
||||||
PlayState.storyDifficulty = curDifficulty;
|
PlayState.storyDifficulty = curDifficulty;
|
||||||
|
PlayState.storyDifficulty_NEW = 'easy';
|
||||||
|
|
||||||
grpDifficulties.group.forEach(function(spr)
|
grpDifficulties.group.forEach(function(spr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -191,8 +191,10 @@ class InitState extends FlxTransitionableState
|
||||||
var dif = getDif();
|
var dif = getDif();
|
||||||
|
|
||||||
PlayState.currentSong = SongLoad.loadFromJson(song, song);
|
PlayState.currentSong = SongLoad.loadFromJson(song, song);
|
||||||
|
PlayState.currentSong_NEW = SongDataParser.fetchSong(song);
|
||||||
PlayState.isStoryMode = isStoryMode;
|
PlayState.isStoryMode = isStoryMode;
|
||||||
PlayState.storyDifficulty = dif;
|
PlayState.storyDifficulty = dif;
|
||||||
|
PlayState.storyDifficulty_NEW = 'easy';
|
||||||
SongLoad.curDiff = switch (dif)
|
SongLoad.curDiff = switch (dif)
|
||||||
{
|
{
|
||||||
case 0: 'easy';
|
case 0: 'easy';
|
||||||
|
|
|
@ -70,7 +70,7 @@ class LatencyState extends MusicBeatSubstate
|
||||||
|
|
||||||
// funnyStatsGraph.hi
|
// funnyStatsGraph.hi
|
||||||
|
|
||||||
Conductor.bpm = 60;
|
Conductor.forceBPM(60);
|
||||||
|
|
||||||
noteGrp = new FlxTypedGroup<Note>();
|
noteGrp = new FlxTypedGroup<Note>();
|
||||||
add(noteGrp);
|
add(noteGrp);
|
||||||
|
|
|
@ -2,6 +2,8 @@ package funkin;
|
||||||
|
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
|
import funkin.noteStuff.NoteBasic.NoteData;
|
||||||
|
import funkin.noteStuff.NoteBasic.NoteType;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
import funkin.play.Strumline.StrumlineStyle;
|
import funkin.play.Strumline.StrumlineStyle;
|
||||||
import funkin.shaderslmfao.ColorSwap;
|
import funkin.shaderslmfao.ColorSwap;
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
package funkin;
|
package funkin;
|
||||||
|
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.FlxSubState;
|
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.input.keyboard.FlxKey;
|
|
||||||
import flixel.system.FlxSound;
|
import flixel.system.FlxSound;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.Controls.Control;
|
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
|
|
||||||
class PauseSubState extends MusicBeatSubstate
|
class PauseSubState extends MusicBeatSubstate
|
||||||
{
|
{
|
||||||
|
@ -61,7 +59,14 @@ class PauseSubState extends MusicBeatSubstate
|
||||||
add(metaDataGrp);
|
add(metaDataGrp);
|
||||||
|
|
||||||
var levelInfo:FlxText = new FlxText(20, 15, 0, "", 32);
|
var levelInfo:FlxText = new FlxText(20, 15, 0, "", 32);
|
||||||
levelInfo.text += PlayState.currentSong.song;
|
if (PlayState.instance.currentChart != null)
|
||||||
|
{
|
||||||
|
levelInfo.text += '${PlayState.instance.currentChart.songName} - ${PlayState.instance.currentChart.songArtist}';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levelInfo.text += PlayState.currentSong.song;
|
||||||
|
}
|
||||||
levelInfo.scrollFactor.set();
|
levelInfo.scrollFactor.set();
|
||||||
levelInfo.setFormat(Paths.font("vcr.ttf"), 32);
|
levelInfo.setFormat(Paths.font("vcr.ttf"), 32);
|
||||||
levelInfo.updateHitbox();
|
levelInfo.updateHitbox();
|
||||||
|
@ -180,9 +185,11 @@ class PauseSubState extends MusicBeatSubstate
|
||||||
close();
|
close();
|
||||||
case "EASY" | 'NORMAL' | "HARD":
|
case "EASY" | 'NORMAL' | "HARD":
|
||||||
PlayState.currentSong = SongLoad.loadFromJson(PlayState.currentSong.song.toLowerCase(), PlayState.currentSong.song.toLowerCase());
|
PlayState.currentSong = SongLoad.loadFromJson(PlayState.currentSong.song.toLowerCase(), PlayState.currentSong.song.toLowerCase());
|
||||||
|
PlayState.currentSong_NEW = SongDataParser.fetchSong(PlayState.currentSong.song.toLowerCase());
|
||||||
SongLoad.curDiff = daSelected.toLowerCase();
|
SongLoad.curDiff = daSelected.toLowerCase();
|
||||||
|
|
||||||
PlayState.storyDifficulty = curSelected;
|
PlayState.storyDifficulty = curSelected;
|
||||||
|
PlayState.storyDifficulty_NEW = 'easy';
|
||||||
|
|
||||||
PlayState.needsReset = true;
|
PlayState.needsReset = true;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package funkin;
|
||||||
|
|
||||||
import funkin.Section.SwagSection;
|
import funkin.Section.SwagSection;
|
||||||
import funkin.noteStuff.NoteBasic.NoteData;
|
import funkin.noteStuff.NoteBasic.NoteData;
|
||||||
|
import funkin.play.PlayState;
|
||||||
import haxe.Json;
|
import haxe.Json;
|
||||||
import lime.utils.Assets;
|
import lime.utils.Assets;
|
||||||
|
|
||||||
|
@ -47,7 +48,21 @@ class SongLoad
|
||||||
|
|
||||||
public static function loadFromJson(jsonInput:String, ?folder:String):SwagSong
|
public static function loadFromJson(jsonInput:String, ?folder:String):SwagSong
|
||||||
{
|
{
|
||||||
var rawJson = Assets.getText(Paths.json('songs/${folder.toLowerCase()}/${jsonInput.toLowerCase()}')).trim();
|
var rawJson:Dynamic = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rawJson = Assets.getText(Paths.json('songs/${folder.toLowerCase()}/${jsonInput.toLowerCase()}')).trim();
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
trace('Failed to load song data: ${e}');
|
||||||
|
rawJson = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawJson == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
while (!rawJson.endsWith("}"))
|
while (!rawJson.endsWith("}"))
|
||||||
{
|
{
|
||||||
|
@ -112,6 +127,11 @@ class SongLoad
|
||||||
|
|
||||||
public static function getSpeed(?diff:String):Float
|
public static function getSpeed(?diff:String):Float
|
||||||
{
|
{
|
||||||
|
if (PlayState.instance != null && PlayState.instance.currentChart != null)
|
||||||
|
{
|
||||||
|
return getSpeed_NEW(diff);
|
||||||
|
}
|
||||||
|
|
||||||
if (diff == null)
|
if (diff == null)
|
||||||
diff = SongLoad.curDiff;
|
diff = SongLoad.curDiff;
|
||||||
|
|
||||||
|
@ -137,6 +157,14 @@ class SongLoad
|
||||||
return speedShit;
|
return speedShit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getSpeed_NEW(?diff:String):Float
|
||||||
|
{
|
||||||
|
if (PlayState.instance == null || PlayState.instance.currentChart == null || PlayState.instance.currentChart.scrollSpeed == 0.0)
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
|
return PlayState.instance.currentChart.scrollSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
public static function getDefaultSwagSong():SwagSong
|
public static function getDefaultSwagSong():SwagSong
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.MenuItem.WeekType;
|
import funkin.MenuItem.WeekType;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
import lime.net.curl.CURLCode;
|
import lime.net.curl.CURLCode;
|
||||||
import openfl.Assets;
|
import openfl.Assets;
|
||||||
|
|
||||||
|
@ -372,10 +373,12 @@ class StoryMenuState extends MusicBeatState
|
||||||
selectedWeek = true;
|
selectedWeek = true;
|
||||||
|
|
||||||
PlayState.currentSong = SongLoad.loadFromJson(PlayState.storyPlaylist[0].toLowerCase(), PlayState.storyPlaylist[0].toLowerCase());
|
PlayState.currentSong = SongLoad.loadFromJson(PlayState.storyPlaylist[0].toLowerCase(), PlayState.storyPlaylist[0].toLowerCase());
|
||||||
|
PlayState.currentSong_NEW = SongDataParser.fetchSong(PlayState.storyPlaylist[0].toLowerCase());
|
||||||
PlayState.storyWeek = curWeek;
|
PlayState.storyWeek = curWeek;
|
||||||
PlayState.campaignScore = 0;
|
PlayState.campaignScore = 0;
|
||||||
|
|
||||||
PlayState.storyDifficulty = curDifficulty;
|
PlayState.storyDifficulty = curDifficulty;
|
||||||
|
PlayState.storyDifficulty_NEW = 'easy';
|
||||||
SongLoad.curDiff = switch (curDifficulty)
|
SongLoad.curDiff = switch (curDifficulty)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
@ -140,7 +140,7 @@ class TitleState extends MusicBeatState
|
||||||
{
|
{
|
||||||
FlxG.sound.playMusic(Paths.music('freakyMenu'), 0);
|
FlxG.sound.playMusic(Paths.music('freakyMenu'), 0);
|
||||||
FlxG.sound.music.fadeIn(4, 0, 0.7);
|
FlxG.sound.music.fadeIn(4, 0, 0.7);
|
||||||
Conductor.bpm = Constants.FREAKY_MENU_BPM;
|
Conductor.forceBPM(Constants.FREAKY_MENU_BPM);
|
||||||
}
|
}
|
||||||
|
|
||||||
persistentUpdate = true;
|
persistentUpdate = true;
|
||||||
|
@ -474,7 +474,7 @@ class TitleState extends MusicBeatState
|
||||||
var spec:SpectogramSprite = new SpectogramSprite(FlxG.sound.music);
|
var spec:SpectogramSprite = new SpectogramSprite(FlxG.sound.music);
|
||||||
add(spec);
|
add(spec);
|
||||||
|
|
||||||
Conductor.bpm = 190;
|
Conductor.forceBPM(190);
|
||||||
FlxG.camera.flash(FlxColor.WHITE, 1);
|
FlxG.camera.flash(FlxColor.WHITE, 1);
|
||||||
FlxG.sound.play(Paths.sound('confirmMenu'), 0.7);
|
FlxG.sound.play(Paths.sound('confirmMenu'), 0.7);
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,7 @@ class ChartingState extends MusicBeatState
|
||||||
updateGrid();
|
updateGrid();
|
||||||
|
|
||||||
loadSong(_song.song);
|
loadSong(_song.song);
|
||||||
Conductor.bpm = _song.bpm;
|
// Conductor.bpm = _song.bpm;
|
||||||
Conductor.mapBPMChanges(_song);
|
Conductor.mapBPMChanges(_song);
|
||||||
|
|
||||||
bpmTxt = new FlxText(1000, 50, 0, "", 16);
|
bpmTxt = new FlxText(1000, 50, 0, "", 16);
|
||||||
|
@ -549,7 +549,7 @@ class ChartingState extends MusicBeatState
|
||||||
{
|
{
|
||||||
tempBpm = nums.value;
|
tempBpm = nums.value;
|
||||||
Conductor.mapBPMChanges(_song);
|
Conductor.mapBPMChanges(_song);
|
||||||
Conductor.bpm = nums.value;
|
Conductor.forceBPM(nums.value);
|
||||||
}
|
}
|
||||||
else if (wname == 'note_susLength')
|
else if (wname == 'note_susLength')
|
||||||
{
|
{
|
||||||
|
@ -1223,7 +1223,7 @@ class ChartingState extends MusicBeatState
|
||||||
|
|
||||||
if (SongLoad.getSong()[curSection].changeBPM && SongLoad.getSong()[curSection].bpm > 0)
|
if (SongLoad.getSong()[curSection].changeBPM && SongLoad.getSong()[curSection].bpm > 0)
|
||||||
{
|
{
|
||||||
Conductor.bpm = SongLoad.getSong()[curSection].bpm;
|
Conductor.forceBPM(SongLoad.getSong()[curSection].bpm);
|
||||||
FlxG.log.add('CHANGED BPM!');
|
FlxG.log.add('CHANGED BPM!');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1233,7 +1233,7 @@ class ChartingState extends MusicBeatState
|
||||||
for (i in 0...curSection)
|
for (i in 0...curSection)
|
||||||
if (SongLoad.getSong()[i].changeBPM)
|
if (SongLoad.getSong()[i].changeBPM)
|
||||||
daBPM = SongLoad.getSong()[i].bpm;
|
daBPM = SongLoad.getSong()[i].bpm;
|
||||||
Conductor.bpm = daBPM;
|
Conductor.forceBPM(daBPM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* // PORT BULLSHIT, INCASE THERE'S NO SUSTAIN DATA FOR A NOTE
|
/* // PORT BULLSHIT, INCASE THERE'S NO SUSTAIN DATA FOR A NOTE
|
||||||
|
|
|
@ -5,6 +5,7 @@ import flixel.addons.effects.FlxTrail;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.util.FlxDirectionFlags;
|
||||||
import funkin.audiovis.PolygonSpectogram;
|
import funkin.audiovis.PolygonSpectogram;
|
||||||
import funkin.noteStuff.NoteBasic.NoteData;
|
import funkin.noteStuff.NoteBasic.NoteData;
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ class PicoFight extends MusicBeatState
|
||||||
FlxG.sound.playMusic(Paths.inst("blazin"));
|
FlxG.sound.playMusic(Paths.inst("blazin"));
|
||||||
|
|
||||||
SongLoad.loadFromJson('blazin', "blazin");
|
SongLoad.loadFromJson('blazin', "blazin");
|
||||||
Conductor.bpm = SongLoad.songData.bpm;
|
Conductor.forceBPM(SongLoad.songData.bpm);
|
||||||
|
|
||||||
for (dumbassSection in SongLoad.songData.noteMap['hard'])
|
for (dumbassSection in SongLoad.songData.noteMap['hard'])
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,10 @@ import funkin.play.Strumline.StrumlineStyle;
|
||||||
import funkin.play.character.BaseCharacter;
|
import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import funkin.play.scoring.Scoring;
|
import funkin.play.scoring.Scoring;
|
||||||
|
import funkin.play.song.Song;
|
||||||
|
import funkin.play.song.SongData.SongNoteData;
|
||||||
|
import funkin.play.song.SongData.SongPlayableChar;
|
||||||
|
import funkin.play.song.SongValidator;
|
||||||
import funkin.play.stage.Stage;
|
import funkin.play.stage.Stage;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.play.stage.StageData;
|
||||||
import funkin.ui.PopUpStuff;
|
import funkin.ui.PopUpStuff;
|
||||||
|
@ -62,6 +66,8 @@ class PlayState extends MusicBeatState
|
||||||
*/
|
*/
|
||||||
public static var currentSong:SwagSong = null;
|
public static var currentSong:SwagSong = null;
|
||||||
|
|
||||||
|
public static var currentSong_NEW:Song = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the game is currently in Story Mode. If false, we are in Free Play Mode.
|
* Whether the game is currently in Story Mode. If false, we are in Free Play Mode.
|
||||||
*/
|
*/
|
||||||
|
@ -116,6 +122,8 @@ class PlayState extends MusicBeatState
|
||||||
*/
|
*/
|
||||||
public var currentStage:Stage = null;
|
public var currentStage:Stage = null;
|
||||||
|
|
||||||
|
public var currentChart(get, null):SongDifficulty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The internal ID of the currently active Stage.
|
* The internal ID of the currently active Stage.
|
||||||
* Used to retrieve the data required to build the `currentStage`.
|
* Used to retrieve the data required to build the `currentStage`.
|
||||||
|
@ -166,6 +174,12 @@ class PlayState extends MusicBeatState
|
||||||
*/
|
*/
|
||||||
private var healthLerp:Float = 1;
|
private var healthLerp:Float = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcibly disables all update logic while the game moves back to the Menu state.
|
||||||
|
* This is used only when a critical error occurs and the game cannot continue.
|
||||||
|
*/
|
||||||
|
private var criticalFailure:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RENDER OBJECTS
|
* RENDER OBJECTS
|
||||||
*/
|
*/
|
||||||
|
@ -244,6 +258,7 @@ class PlayState extends MusicBeatState
|
||||||
public static var storyWeek:Int = 0;
|
public static var storyWeek:Int = 0;
|
||||||
public static var storyPlaylist:Array<String> = [];
|
public static var storyPlaylist:Array<String> = [];
|
||||||
public static var storyDifficulty:Int = 1;
|
public static var storyDifficulty:Int = 1;
|
||||||
|
public static var storyDifficulty_NEW:String = "normal";
|
||||||
public static var seenCutscene:Bool = false;
|
public static var seenCutscene:Bool = false;
|
||||||
public static var campaignScore:Int = 0;
|
public static var campaignScore:Int = 0;
|
||||||
|
|
||||||
|
@ -279,8 +294,10 @@ class PlayState extends MusicBeatState
|
||||||
{
|
{
|
||||||
super.create();
|
super.create();
|
||||||
|
|
||||||
if (currentSong == null)
|
if (currentSong == null && currentSong_NEW == null)
|
||||||
{
|
{
|
||||||
|
criticalFailure = true;
|
||||||
|
|
||||||
lime.app.Application.current.window.alert("There was a critical error while accessing the selected song. Click OK to return to the main menu.",
|
lime.app.Application.current.window.alert("There was a critical error while accessing the selected song. Click OK to return to the main menu.",
|
||||||
"Error loading PlayState");
|
"Error loading PlayState");
|
||||||
FlxG.switchState(new MainMenuState());
|
FlxG.switchState(new MainMenuState());
|
||||||
|
@ -308,28 +325,48 @@ class PlayState extends MusicBeatState
|
||||||
FlxG.sound.music.stop();
|
FlxG.sound.music.stop();
|
||||||
|
|
||||||
// Prepare the current song to be played.
|
// Prepare the current song to be played.
|
||||||
FlxG.sound.cache(Paths.inst(currentSong.song));
|
if (currentChart != null)
|
||||||
FlxG.sound.cache(Paths.voices(currentSong.song));
|
{
|
||||||
|
currentChart.cacheInst();
|
||||||
|
currentChart.cacheVocals();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.sound.cache(Paths.inst(currentSong.song));
|
||||||
|
FlxG.sound.cache(Paths.voices(currentSong.song));
|
||||||
|
}
|
||||||
|
|
||||||
Conductor.songPosition = -5000;
|
Conductor.update(-5000);
|
||||||
|
|
||||||
// Initialize stage stuff.
|
// Initialize stage stuff.
|
||||||
initCameras();
|
initCameras();
|
||||||
|
|
||||||
if (currentSong == null)
|
if (currentSong == null && currentSong_NEW == null)
|
||||||
currentSong = SongLoad.loadFromJson('tutorial');
|
|
||||||
|
|
||||||
Conductor.mapBPMChanges(currentSong);
|
|
||||||
Conductor.bpm = currentSong.bpm;
|
|
||||||
|
|
||||||
switch (currentSong.song.toLowerCase())
|
|
||||||
{
|
{
|
||||||
case 'senpai':
|
currentSong = SongLoad.loadFromJson('tutorial');
|
||||||
dialogue = CoolUtil.coolTextFile(Paths.txt('songs/senpai/senpaiDialogue'));
|
}
|
||||||
case 'roses':
|
|
||||||
dialogue = CoolUtil.coolTextFile(Paths.txt('songs/roses/rosesDialogue'));
|
if (currentSong_NEW != null)
|
||||||
case 'thorns':
|
{
|
||||||
dialogue = CoolUtil.coolTextFile(Paths.txt('songs/thorns/thornsDialogue'));
|
Conductor.mapTimeChanges(currentChart);
|
||||||
|
// Conductor.bpm = currentChart.getStartingBPM();
|
||||||
|
|
||||||
|
// TODO: Support for dialog.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Conductor.mapBPMChanges(currentSong);
|
||||||
|
// Conductor.bpm = currentSong.bpm;
|
||||||
|
|
||||||
|
switch (currentSong.song.toLowerCase())
|
||||||
|
{
|
||||||
|
case 'senpai':
|
||||||
|
dialogue = CoolUtil.coolTextFile(Paths.txt('songs/senpai/senpaiDialogue'));
|
||||||
|
case 'roses':
|
||||||
|
dialogue = CoolUtil.coolTextFile(Paths.txt('songs/roses/rosesDialogue'));
|
||||||
|
case 'thorns':
|
||||||
|
dialogue = CoolUtil.coolTextFile(Paths.txt('songs/thorns/thornsDialogue'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dialogue != null)
|
if (dialogue != null)
|
||||||
|
@ -379,7 +416,14 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
add(grpNoteSplashes);
|
add(grpNoteSplashes);
|
||||||
|
|
||||||
generateSong();
|
if (currentSong_NEW != null)
|
||||||
|
{
|
||||||
|
generateSong_NEW();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
generateSong();
|
||||||
|
}
|
||||||
|
|
||||||
resetCamera();
|
resetCamera();
|
||||||
|
|
||||||
|
@ -442,6 +486,13 @@ class PlayState extends MusicBeatState
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_currentChart():SongDifficulty
|
||||||
|
{
|
||||||
|
if (currentSong_NEW == null || storyDifficulty_NEW == null)
|
||||||
|
return null;
|
||||||
|
return currentSong_NEW.getDifficulty(storyDifficulty_NEW);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the game and HUD cameras.
|
* Initializes the game and HUD cameras.
|
||||||
*/
|
*/
|
||||||
|
@ -460,6 +511,12 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
function initStage()
|
function initStage()
|
||||||
{
|
{
|
||||||
|
if (currentSong_NEW != null)
|
||||||
|
{
|
||||||
|
initStage_NEW();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Move stageId to the song file.
|
// TODO: Move stageId to the song file.
|
||||||
switch (currentSong.song.toLowerCase())
|
switch (currentSong.song.toLowerCase())
|
||||||
{
|
{
|
||||||
|
@ -487,9 +544,6 @@ class PlayState extends MusicBeatState
|
||||||
currentStageId = 'schoolEvil';
|
currentStageId = 'schoolEvil';
|
||||||
case 'guns' | 'stress' | 'ugh':
|
case 'guns' | 'stress' | 'ugh':
|
||||||
currentStageId = 'tankmanBattlefield';
|
currentStageId = 'tankmanBattlefield';
|
||||||
case 'experimental-phase' | 'perfection':
|
|
||||||
// SERIOUSLY REVAMP THE CHART FORMAT ALREADY
|
|
||||||
currentStageId = "breakout";
|
|
||||||
default:
|
default:
|
||||||
currentStageId = "mainStage";
|
currentStageId = "mainStage";
|
||||||
}
|
}
|
||||||
|
@ -497,8 +551,33 @@ class PlayState extends MusicBeatState
|
||||||
loadStage(currentStageId);
|
loadStage(currentStageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initStage_NEW()
|
||||||
|
{
|
||||||
|
if (currentChart == null)
|
||||||
|
{
|
||||||
|
trace('Song difficulty could not be loaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentChart.stage != null && currentChart.stage != '')
|
||||||
|
{
|
||||||
|
currentStageId = currentChart.stage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentStageId = SongValidator.DEFAULT_STAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadStage(currentStageId);
|
||||||
|
}
|
||||||
|
|
||||||
function initCharacters()
|
function initCharacters()
|
||||||
{
|
{
|
||||||
|
if (currentSong_NEW != null)
|
||||||
|
{
|
||||||
|
initCharacters_NEW();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
iconP1 = new HealthIcon(currentSong.player1, 0);
|
iconP1 = new HealthIcon(currentSong.player1, 0);
|
||||||
iconP1.y = healthBar.y - (iconP1.height / 2);
|
iconP1.y = healthBar.y - (iconP1.height / 2);
|
||||||
add(iconP1);
|
add(iconP1);
|
||||||
|
@ -615,6 +694,111 @@ class PlayState extends MusicBeatState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initCharacters_NEW()
|
||||||
|
{
|
||||||
|
if (currentSong_NEW == null || currentChart == null)
|
||||||
|
{
|
||||||
|
trace('Song difficulty could not be loaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Switch playable character by manipulating this value.
|
||||||
|
// TODO: How to choose which one to use for story mode?
|
||||||
|
var currentPlayer = 'bf';
|
||||||
|
|
||||||
|
var currentCharData:SongPlayableChar = currentChart.getPlayableChar(currentPlayer);
|
||||||
|
|
||||||
|
//
|
||||||
|
// GIRLFRIEND
|
||||||
|
//
|
||||||
|
var girlfriend:BaseCharacter = CharacterDataParser.fetchCharacter(currentCharData.girlfriend);
|
||||||
|
|
||||||
|
if (girlfriend != null)
|
||||||
|
{
|
||||||
|
girlfriend.characterType = CharacterType.GF;
|
||||||
|
}
|
||||||
|
else if (currentCharData.girlfriend != '')
|
||||||
|
{
|
||||||
|
trace('WARNING: Could not load girlfriend character with ID ${currentCharData.girlfriend}, skipping...');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Chosen GF was '' so we don't load one.
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DAD
|
||||||
|
//
|
||||||
|
var dad:BaseCharacter = CharacterDataParser.fetchCharacter(currentCharData.opponent);
|
||||||
|
|
||||||
|
if (dad != null)
|
||||||
|
{
|
||||||
|
dad.characterType = CharacterType.DAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Cut out this code/make it generic.
|
||||||
|
switch (currentCharData.opponent)
|
||||||
|
{
|
||||||
|
case 'gf':
|
||||||
|
if (isStoryMode)
|
||||||
|
{
|
||||||
|
cameraFollowPoint.x += 600;
|
||||||
|
tweenCamIn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// OPPONENT HEALTH ICON
|
||||||
|
//
|
||||||
|
iconP2 = new HealthIcon(currentCharData.opponent, 1);
|
||||||
|
iconP2.y = healthBar.y - (iconP2.height / 2);
|
||||||
|
add(iconP2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// BOYFRIEND
|
||||||
|
//
|
||||||
|
var boyfriend:BaseCharacter = CharacterDataParser.fetchCharacter(currentPlayer);
|
||||||
|
|
||||||
|
if (boyfriend != null)
|
||||||
|
{
|
||||||
|
boyfriend.characterType = CharacterType.BF;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PLAYER HEALTH ICON
|
||||||
|
//
|
||||||
|
iconP1 = new HealthIcon(currentPlayer, 0);
|
||||||
|
iconP1.y = healthBar.y - (iconP1.height / 2);
|
||||||
|
add(iconP1);
|
||||||
|
|
||||||
|
//
|
||||||
|
// ADD CHARACTERS TO SCENE
|
||||||
|
//
|
||||||
|
|
||||||
|
if (currentStage != null)
|
||||||
|
{
|
||||||
|
// Characters get added to the stage, not the main scene.
|
||||||
|
if (girlfriend != null)
|
||||||
|
{
|
||||||
|
currentStage.addCharacter(girlfriend, GF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boyfriend != null)
|
||||||
|
{
|
||||||
|
currentStage.addCharacter(boyfriend, BF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dad != null)
|
||||||
|
{
|
||||||
|
currentStage.addCharacter(dad, DAD);
|
||||||
|
// Camera starts at dad.
|
||||||
|
cameraFollowPoint.setPosition(dad.cameraFocusPoint.x, dad.cameraFocusPoint.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rearrange by z-indexes.
|
||||||
|
currentStage.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any references to the current stage, then clears the stage cache,
|
* Removes any references to the current stage, then clears the stage cache,
|
||||||
* then reloads all the stages.
|
* then reloads all the stages.
|
||||||
|
@ -794,7 +978,14 @@ class PlayState extends MusicBeatState
|
||||||
// if (FlxG.sound.music != null)
|
// if (FlxG.sound.music != null)
|
||||||
// FlxG.sound.music.play(true);
|
// FlxG.sound.music.play(true);
|
||||||
// else
|
// else
|
||||||
FlxG.sound.playMusic(Paths.inst(currentSong.song), 1, false);
|
if (currentChart != null)
|
||||||
|
{
|
||||||
|
currentChart.playInst(1.0, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.sound.playMusic(Paths.inst(currentSong.song), 1, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlxG.sound.music.onComplete = endSong;
|
FlxG.sound.music.onComplete = endSong;
|
||||||
|
@ -813,7 +1004,7 @@ class PlayState extends MusicBeatState
|
||||||
{
|
{
|
||||||
// FlxG.log.add(ChartParser.parse());
|
// FlxG.log.add(ChartParser.parse());
|
||||||
|
|
||||||
Conductor.bpm = currentSong.bpm;
|
Conductor.forceBPM(currentSong.bpm);
|
||||||
|
|
||||||
currentSong.song = currentSong.song;
|
currentSong.song = currentSong.song;
|
||||||
|
|
||||||
|
@ -836,6 +1027,32 @@ class PlayState extends MusicBeatState
|
||||||
generatedMusic = true;
|
generatedMusic = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function generateSong_NEW():Void
|
||||||
|
{
|
||||||
|
if (currentChart == null)
|
||||||
|
{
|
||||||
|
trace('Song difficulty could not be loaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Conductor.forceBPM(currentChart.getStartingBPM());
|
||||||
|
|
||||||
|
// TODO: Fix grouped vocals
|
||||||
|
vocals = currentChart.buildVocals();
|
||||||
|
vocals.members[0].onComplete = function()
|
||||||
|
{
|
||||||
|
vocalsFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the rendered note group.
|
||||||
|
activeNotes = new FlxTypedGroup<Note>();
|
||||||
|
activeNotes.zIndex = 1000;
|
||||||
|
add(activeNotes);
|
||||||
|
|
||||||
|
regenNoteData_NEW();
|
||||||
|
|
||||||
|
generatedMusic = true;
|
||||||
|
}
|
||||||
|
|
||||||
function regenNoteData():Void
|
function regenNoteData():Void
|
||||||
{
|
{
|
||||||
// make unspawn notes shit def empty
|
// make unspawn notes shit def empty
|
||||||
|
@ -950,6 +1167,133 @@ class PlayState extends MusicBeatState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function regenNoteData_NEW():Void
|
||||||
|
{
|
||||||
|
// Destroy inactive notes.
|
||||||
|
inactiveNotes = [];
|
||||||
|
|
||||||
|
// Destroy active notes.
|
||||||
|
activeNotes.forEach(function(nt)
|
||||||
|
{
|
||||||
|
nt.followsTime = false;
|
||||||
|
FlxTween.tween(nt, {y: FlxG.height + nt.y}, 0.5, {
|
||||||
|
ease: FlxEase.expoIn,
|
||||||
|
onComplete: function(twn)
|
||||||
|
{
|
||||||
|
nt.kill();
|
||||||
|
activeNotes.remove(nt, true);
|
||||||
|
nt.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var noteData:Array<SongNoteData> = currentChart.notes;
|
||||||
|
|
||||||
|
var oldNote:Note = null;
|
||||||
|
for (songNote in noteData)
|
||||||
|
{
|
||||||
|
var mustHitNote:Bool = songNote.getMustHitNote();
|
||||||
|
|
||||||
|
// TODO: Put this in the chart or something?
|
||||||
|
var strumlineStyle:StrumlineStyle = null;
|
||||||
|
switch (currentStageId)
|
||||||
|
{
|
||||||
|
case 'school':
|
||||||
|
strumlineStyle = PIXEL;
|
||||||
|
case 'schoolEvil':
|
||||||
|
strumlineStyle = PIXEL;
|
||||||
|
default:
|
||||||
|
strumlineStyle = NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newNote:Note = new Note(songNote.time, songNote.data, oldNote, false, strumlineStyle);
|
||||||
|
newNote.mustPress = mustHitNote;
|
||||||
|
newNote.data.sustainLength = songNote.length;
|
||||||
|
newNote.data.noteKind = songNote.kind;
|
||||||
|
newNote.scrollFactor.set(0, 0);
|
||||||
|
|
||||||
|
// Note positioning.
|
||||||
|
// TODO: Make this more robust.
|
||||||
|
if (newNote.mustPress)
|
||||||
|
{
|
||||||
|
if (playerStrumline != null)
|
||||||
|
{
|
||||||
|
// Align with the strumline arrow.
|
||||||
|
newNote.x = playerStrumline.getArrow(songNote.getDirection()).x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Assume strumline position.
|
||||||
|
newNote.x += FlxG.width / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (enemyStrumline != null)
|
||||||
|
{
|
||||||
|
newNote.x = enemyStrumline.getArrow(songNote.getDirection()).x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// newNote.x += 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inactiveNotes.push(newNote);
|
||||||
|
|
||||||
|
oldNote = newNote;
|
||||||
|
|
||||||
|
// Generate X sustain notes.
|
||||||
|
var sustainSections = Math.round(songNote.length / Conductor.stepCrochet);
|
||||||
|
for (noteIndex in 0...sustainSections)
|
||||||
|
{
|
||||||
|
var noteTimeOffset:Float = Conductor.stepCrochet + (Conductor.stepCrochet * noteIndex);
|
||||||
|
var sustainNote:Note = new Note(songNote.time + noteTimeOffset, songNote.data, oldNote, true, strumlineStyle);
|
||||||
|
sustainNote.mustPress = mustHitNote;
|
||||||
|
sustainNote.data.noteKind = songNote.kind;
|
||||||
|
sustainNote.scrollFactor.set(0, 0);
|
||||||
|
|
||||||
|
if (sustainNote.mustPress)
|
||||||
|
{
|
||||||
|
if (playerStrumline != null)
|
||||||
|
{
|
||||||
|
// Align with the strumline arrow.
|
||||||
|
sustainNote.x = playerStrumline.getArrow(songNote.getDirection()).x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Assume strumline position.
|
||||||
|
sustainNote.x += FlxG.width / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (enemyStrumline != null)
|
||||||
|
{
|
||||||
|
sustainNote.x = enemyStrumline.getArrow(songNote.getDirection()).x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// newNote.x += 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inactiveNotes.push(sustainNote);
|
||||||
|
|
||||||
|
oldNote = sustainNote;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorting is an expensive operation.
|
||||||
|
// Assume it was done in the chart file.
|
||||||
|
/**
|
||||||
|
inactiveNotes.sort(function(a:Note, b:Note):Int
|
||||||
|
{
|
||||||
|
return SortUtil.byStrumtime(FlxSort.ASCENDING, a, b);
|
||||||
|
});
|
||||||
|
**/
|
||||||
|
}
|
||||||
|
|
||||||
function tweenCamIn():Void
|
function tweenCamIn():Void
|
||||||
{
|
{
|
||||||
FlxTween.tween(FlxG.camera, {zoom: 1.3 * FlxCamera.defaultZoom}, (Conductor.stepCrochet * 4 / 1000), {ease: FlxEase.elasticInOut});
|
FlxTween.tween(FlxG.camera, {zoom: 1.3 * FlxCamera.defaultZoom}, (Conductor.stepCrochet * 4 / 1000), {ease: FlxEase.elasticInOut});
|
||||||
|
@ -986,7 +1330,7 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
vocals.pause();
|
vocals.pause();
|
||||||
FlxG.sound.music.play();
|
FlxG.sound.music.play();
|
||||||
Conductor.songPosition = FlxG.sound.music.time + Conductor.offset;
|
Conductor.update(FlxG.sound.music.time + Conductor.offset);
|
||||||
|
|
||||||
if (vocalsFinished)
|
if (vocalsFinished)
|
||||||
return;
|
return;
|
||||||
|
@ -999,6 +1343,9 @@ class PlayState extends MusicBeatState
|
||||||
{
|
{
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (criticalFailure)
|
||||||
|
return;
|
||||||
|
|
||||||
if (FlxG.keys.justPressed.U)
|
if (FlxG.keys.justPressed.U)
|
||||||
{
|
{
|
||||||
// hack for HaxeUI generation, doesn't work unless persistentUpdate is false at state creation!!
|
// hack for HaxeUI generation, doesn't work unless persistentUpdate is false at state creation!!
|
||||||
|
@ -1027,7 +1374,16 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
currentStage.resetStage();
|
currentStage.resetStage();
|
||||||
|
|
||||||
regenNoteData(); // loads the note data from start
|
// Delete all notes and reset the arrays.
|
||||||
|
if (currentChart != null)
|
||||||
|
{
|
||||||
|
regenNoteData_NEW();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
regenNoteData();
|
||||||
|
}
|
||||||
|
|
||||||
health = 1;
|
health = 1;
|
||||||
songScore = 0;
|
songScore = 0;
|
||||||
combo = 0;
|
combo = 0;
|
||||||
|
@ -1058,7 +1414,7 @@ class PlayState extends MusicBeatState
|
||||||
if (Paths.SOUND_EXT == 'mp3')
|
if (Paths.SOUND_EXT == 'mp3')
|
||||||
Conductor.offset = -13; // DO NOT FORGET TO REMOVE THE HARDCODE! WHEN I MAKE BETTER OFFSET SYSTEM!
|
Conductor.offset = -13; // DO NOT FORGET TO REMOVE THE HARDCODE! WHEN I MAKE BETTER OFFSET SYSTEM!
|
||||||
|
|
||||||
Conductor.songPosition = FlxG.sound.music.time + Conductor.offset; // 20 is THE MILLISECONDS??
|
Conductor.update(FlxG.sound.music.time + Conductor.offset);
|
||||||
|
|
||||||
if (!isGamePaused)
|
if (!isGamePaused)
|
||||||
{
|
{
|
||||||
|
@ -1177,7 +1533,7 @@ class PlayState extends MusicBeatState
|
||||||
}
|
}
|
||||||
FlxG.watch.addQuick("songPos", Conductor.songPosition);
|
FlxG.watch.addQuick("songPos", Conductor.songPosition);
|
||||||
|
|
||||||
if (currentSong.song == 'Fresh')
|
if (currentSong != null && currentSong.song == 'Fresh')
|
||||||
{
|
{
|
||||||
switch (curBeat)
|
switch (curBeat)
|
||||||
{
|
{
|
||||||
|
@ -1307,7 +1663,7 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
if (!daNote.mustPress && daNote.wasGoodHit && !daNote.tooLate)
|
if (!daNote.mustPress && daNote.wasGoodHit && !daNote.tooLate)
|
||||||
{
|
{
|
||||||
if (currentSong.song != 'Tutorial')
|
if (currentSong != null && currentSong.song != 'Tutorial')
|
||||||
camZooming = true;
|
camZooming = true;
|
||||||
|
|
||||||
var event:NoteScriptEvent = new NoteScriptEvent(ScriptEvent.NOTE_HIT, daNote, combo, true);
|
var event:NoteScriptEvent = new NoteScriptEvent(ScriptEvent.NOTE_HIT, daNote, combo, true);
|
||||||
|
@ -1324,7 +1680,7 @@ class PlayState extends MusicBeatState
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Volume of DAD.
|
// Volume of DAD.
|
||||||
if (currentSong.needsVoices)
|
if (currentSong != null && currentSong.needsVoices)
|
||||||
vocals.volume = 1;
|
vocals.volume = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1412,8 +1768,9 @@ class PlayState extends MusicBeatState
|
||||||
}
|
}
|
||||||
daPos += 4 * (1000 * 60 / daBPM);
|
daPos += 4 * (1000 * 60 / daBPM);
|
||||||
}
|
}
|
||||||
Conductor.songPosition = FlxG.sound.music.time = daPos;
|
|
||||||
Conductor.songPosition += Conductor.offset;
|
FlxG.sound.music.time = daPos;
|
||||||
|
Conductor.update(FlxG.sound.music.time + Conductor.offset);
|
||||||
updateCurStep();
|
updateCurStep();
|
||||||
resyncVocals();
|
resyncVocals();
|
||||||
}
|
}
|
||||||
|
@ -1857,7 +2214,7 @@ class PlayState extends MusicBeatState
|
||||||
{
|
{
|
||||||
if (SongLoad.getSong()[Math.floor(curStep / 16)].changeBPM)
|
if (SongLoad.getSong()[Math.floor(curStep / 16)].changeBPM)
|
||||||
{
|
{
|
||||||
Conductor.bpm = SongLoad.getSong()[Math.floor(curStep / 16)].bpm;
|
Conductor.forceBPM(SongLoad.getSong()[Math.floor(curStep / 16)].bpm);
|
||||||
FlxG.log.add('CHANGED BPM!');
|
FlxG.log.add('CHANGED BPM!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2118,8 +2475,14 @@ class PlayState extends MusicBeatState
|
||||||
function performCleanup()
|
function performCleanup()
|
||||||
{
|
{
|
||||||
// Uncache the song.
|
// Uncache the song.
|
||||||
openfl.utils.Assets.cache.clear(Paths.inst(currentSong.song));
|
if (currentChart != null)
|
||||||
openfl.utils.Assets.cache.clear(Paths.voices(currentSong.song));
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
openfl.utils.Assets.cache.clear(Paths.inst(currentSong.song));
|
||||||
|
openfl.utils.Assets.cache.clear(Paths.voices(currentSong.song));
|
||||||
|
}
|
||||||
|
|
||||||
// Remove reference to stage and remove sprites from it to save memory.
|
// Remove reference to stage and remove sprites from it to save memory.
|
||||||
if (currentStage != null)
|
if (currentStage != null)
|
||||||
|
|
|
@ -4,9 +4,11 @@ import flixel.FlxSprite;
|
||||||
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
import funkin.noteStuff.NoteBasic.NoteColor;
|
import funkin.noteStuff.NoteBasic.NoteColor;
|
||||||
import funkin.noteStuff.NoteBasic.NoteDir;
|
import funkin.noteStuff.NoteBasic.NoteDir;
|
||||||
import funkin.noteStuff.NoteBasic.NoteType;
|
import funkin.noteStuff.NoteBasic.NoteType;
|
||||||
|
import funkin.ui.PreferencesMenu;
|
||||||
import funkin.util.Constants;
|
import funkin.util.Constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -273,6 +273,10 @@ class BaseCharacter extends Bopper
|
||||||
{
|
{
|
||||||
if (!isOpponent)
|
if (!isOpponent)
|
||||||
{
|
{
|
||||||
|
if (PlayState.instance.iconP1 == null)
|
||||||
|
{
|
||||||
|
trace('[WARN] Player 1 health icon not found!');
|
||||||
|
}
|
||||||
PlayState.instance.iconP1.characterId = _data.healthIcon.id;
|
PlayState.instance.iconP1.characterId = _data.healthIcon.id;
|
||||||
PlayState.instance.iconP1.size.set(_data.healthIcon.scale, _data.healthIcon.scale);
|
PlayState.instance.iconP1.size.set(_data.healthIcon.scale, _data.healthIcon.scale);
|
||||||
PlayState.instance.iconP1.offset.x = _data.healthIcon.offsets[0];
|
PlayState.instance.iconP1.offset.x = _data.healthIcon.offsets[0];
|
||||||
|
@ -281,6 +285,10 @@ class BaseCharacter extends Bopper
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (PlayState.instance.iconP2 == null)
|
||||||
|
{
|
||||||
|
trace('[WARN] Player 2 health icon not found!');
|
||||||
|
}
|
||||||
PlayState.instance.iconP2.characterId = _data.healthIcon.id;
|
PlayState.instance.iconP2.characterId = _data.healthIcon.id;
|
||||||
PlayState.instance.iconP2.size.set(_data.healthIcon.scale, _data.healthIcon.scale);
|
PlayState.instance.iconP2.size.set(_data.healthIcon.scale, _data.healthIcon.scale);
|
||||||
PlayState.instance.iconP2.offset.x = _data.healthIcon.offsets[0];
|
PlayState.instance.iconP2.offset.x = _data.healthIcon.offsets[0];
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package funkin.play.song;
|
package funkin.play.song;
|
||||||
|
|
||||||
|
import funkin.VoicesGroup;
|
||||||
|
import funkin.play.song.SongData.SongChartData;
|
||||||
import funkin.play.song.SongData.SongDataParser;
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
import funkin.play.song.SongData.SongEventData;
|
import funkin.play.song.SongData.SongEventData;
|
||||||
import funkin.play.song.SongData.SongMetadata;
|
import funkin.play.song.SongData.SongMetadata;
|
||||||
|
@ -45,14 +47,18 @@ class Song // implements IPlayStateScriptedClass
|
||||||
cacheCharts();
|
cacheCharts();
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateFromMetadata()
|
/**
|
||||||
|
* Populate the song data from the provided metadata,
|
||||||
|
* including data from individual difficulties. Does not load chart data.
|
||||||
|
*/
|
||||||
|
function populateFromMetadata():Void
|
||||||
{
|
{
|
||||||
// Variations may have different artist, time format, generatedBy, etc.
|
// Variations may have different artist, time format, generatedBy, etc.
|
||||||
for (metadata in _metadata)
|
for (metadata in _metadata)
|
||||||
{
|
{
|
||||||
for (diffId in metadata.playData.difficulties)
|
for (diffId in metadata.playData.difficulties)
|
||||||
{
|
{
|
||||||
var difficulty = new SongDifficulty(diffId, metadata.variation);
|
var difficulty:SongDifficulty = new SongDifficulty(this, diffId, metadata.variation);
|
||||||
|
|
||||||
variations.push(metadata.variation);
|
variations.push(metadata.variation);
|
||||||
|
|
||||||
|
@ -83,25 +89,27 @@ class Song // implements IPlayStateScriptedClass
|
||||||
/**
|
/**
|
||||||
* Parse and cache the chart for all difficulties of this song.
|
* Parse and cache the chart for all difficulties of this song.
|
||||||
*/
|
*/
|
||||||
public function cacheCharts()
|
public function cacheCharts():Void
|
||||||
{
|
{
|
||||||
trace('Caching ${variations.length} chart files for song $songId');
|
trace('Caching ${variations.length} chart files for song $songId');
|
||||||
for (variation in variations)
|
for (variation in variations)
|
||||||
{
|
{
|
||||||
var chartData = SongDataParser.parseSongChartData(songId, variation);
|
var chartData:SongChartData = SongDataParser.parseSongChartData(songId, variation);
|
||||||
|
var chartNotes = chartData.notes;
|
||||||
|
|
||||||
for (diffId in chartData.notes.keys())
|
for (diffId in chartNotes.keys())
|
||||||
{
|
{
|
||||||
trace(' Difficulty $diffId');
|
// Retrieve the cached difficulty data.
|
||||||
var difficulty = difficulties.get(diffId);
|
var difficulty:Null<SongDifficulty> = difficulties.get(diffId);
|
||||||
if (difficulty == null)
|
if (difficulty == null)
|
||||||
{
|
{
|
||||||
trace('Could not find difficulty $diffId for song $songId');
|
trace('Could not find difficulty $diffId for song $songId');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Add the chart data to the difficulty.
|
||||||
difficulty.notes = chartData.notes.get(diffId);
|
difficulty.notes = chartData.notes.get(diffId);
|
||||||
difficulty.scrollSpeed = chartData.scrollSpeed.get(diffId);
|
difficulty.scrollSpeed = chartData.getScrollSpeed(diffId);
|
||||||
|
|
||||||
difficulty.events = chartData.events;
|
difficulty.events = chartData.events;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +119,7 @@ class Song // implements IPlayStateScriptedClass
|
||||||
/**
|
/**
|
||||||
* Retrieve the metadata for a specific difficulty, including the chart if it is loaded.
|
* Retrieve the metadata for a specific difficulty, including the chart if it is loaded.
|
||||||
*/
|
*/
|
||||||
public function getDifficulty(diffId:String):SongDifficulty
|
public inline function getDifficulty(diffId:String):SongDifficulty
|
||||||
{
|
{
|
||||||
return difficulties.get(diffId);
|
return difficulties.get(diffId);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +127,7 @@ class Song // implements IPlayStateScriptedClass
|
||||||
/**
|
/**
|
||||||
* Purge the cached chart data for each difficulty of this song.
|
* Purge the cached chart data for each difficulty of this song.
|
||||||
*/
|
*/
|
||||||
public function clearCharts()
|
public function clearCharts():Void
|
||||||
{
|
{
|
||||||
for (diff in difficulties)
|
for (diff in difficulties)
|
||||||
{
|
{
|
||||||
|
@ -135,6 +143,11 @@ class Song // implements IPlayStateScriptedClass
|
||||||
|
|
||||||
class SongDifficulty
|
class SongDifficulty
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The parent song for this difficulty.
|
||||||
|
*/
|
||||||
|
public final song:Song;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The difficulty ID, such as `easy` or `hard`.
|
* The difficulty ID, such as `easy` or `hard`.
|
||||||
*/
|
*/
|
||||||
|
@ -162,8 +175,9 @@ class SongDifficulty
|
||||||
public var notes:Array<SongNoteData>;
|
public var notes:Array<SongNoteData>;
|
||||||
public var events:Array<SongEventData>;
|
public var events:Array<SongEventData>;
|
||||||
|
|
||||||
public function new(diffId:String, variation:String)
|
public function new(song:Song, diffId:String, variation:String)
|
||||||
{
|
{
|
||||||
|
this.song = song;
|
||||||
this.difficulty = diffId;
|
this.difficulty = diffId;
|
||||||
this.variation = variation;
|
this.variation = variation;
|
||||||
}
|
}
|
||||||
|
@ -172,4 +186,48 @@ class SongDifficulty
|
||||||
{
|
{
|
||||||
notes = null;
|
notes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getStartingBPM():Float
|
||||||
|
{
|
||||||
|
if (timeChanges.length == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeChanges[0].bpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPlayableChar(id:String):SongPlayableChar
|
||||||
|
{
|
||||||
|
return chars.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function cacheInst()
|
||||||
|
{
|
||||||
|
// DEBUG: Remove this.
|
||||||
|
// FlxG.sound.cache(Paths.inst(this.song.songId));
|
||||||
|
FlxG.sound.cache(Paths.inst('bopeebo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function playInst(volume:Float = 1.0, looped:Bool = false)
|
||||||
|
{
|
||||||
|
// DEBUG: Remove this.
|
||||||
|
// FlxG.sound.playMusic(Paths.inst(this.song.songId), volume, looped);
|
||||||
|
FlxG.sound.playMusic(Paths.inst('bopeebo'), volume, looped);
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function cacheVocals()
|
||||||
|
{
|
||||||
|
// DEBUG: Remove this.
|
||||||
|
// FlxG.sound.cache(Paths.voices(this.song.songId));
|
||||||
|
FlxG.sound.cache(Paths.voices('bopeebo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function buildVocals(charId:String = "bf"):VoicesGroup
|
||||||
|
{
|
||||||
|
// DEBUG: Remove this.
|
||||||
|
// var result:VoicesGroup = new VoicesGroup(this.song.songId, null, false);
|
||||||
|
var result:VoicesGroup = new VoicesGroup('bopeebo', null, false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -339,6 +339,11 @@ abstract SongNoteData(RawSongNoteData)
|
||||||
return Math.floor(this.d / strumlineSize);
|
return Math.floor(this.d / strumlineSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public inline function getMustHitNote(strumlineSize:Int = 4):Bool
|
||||||
|
{
|
||||||
|
return getStrumlineIndex(strumlineSize) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
public var length(get, set):Float;
|
public var length(get, set):Float;
|
||||||
|
|
||||||
public function get_length():Float
|
public function get_length():Float
|
||||||
|
@ -522,7 +527,7 @@ abstract SongPlayableChar(RawSongPlayableChar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef SongChartData =
|
typedef RawSongChartData =
|
||||||
{
|
{
|
||||||
var version:Version;
|
var version:Version;
|
||||||
|
|
||||||
|
@ -532,6 +537,32 @@ typedef SongChartData =
|
||||||
var generatedBy:String;
|
var generatedBy:String;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@:forward
|
||||||
|
abstract SongChartData(RawSongChartData)
|
||||||
|
{
|
||||||
|
public function new(scrollSpeed:DynamicAccess<Float>, events:Array<SongEventData>, notes:DynamicAccess<Array<SongNoteData>>)
|
||||||
|
{
|
||||||
|
this = {
|
||||||
|
version: SongMigrator.CHART_VERSION,
|
||||||
|
|
||||||
|
events: events,
|
||||||
|
notes: notes,
|
||||||
|
scrollSpeed: scrollSpeed,
|
||||||
|
generatedBy: SongValidator.DEFAULT_GENERATEDBY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScrollSpeed(diff:String = 'default'):Float
|
||||||
|
{
|
||||||
|
var result:Float = this.scrollSpeed.get(diff);
|
||||||
|
|
||||||
|
if (result == 0.0 && diff != 'default')
|
||||||
|
return getScrollSpeed('default');
|
||||||
|
|
||||||
|
return (result == 0.0) ? 1.0 : result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef RawSongTimeChange =
|
typedef RawSongTimeChange =
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -569,6 +600,17 @@ typedef RawSongTimeChange =
|
||||||
var bt:OneOfTwo<Int, Array<Int>>;
|
var bt:OneOfTwo<Int, Array<Int>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef RawConductorTimeChange =
|
||||||
|
{
|
||||||
|
> RawSongTimeChange,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time in the song (in steps) that this change occurs at.
|
||||||
|
* This time is somewhat weird because the rate it increases is dependent on the BPM at that point in the song.
|
||||||
|
*/
|
||||||
|
public var st:Float;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add aliases to the minimalized property names of the typedef,
|
* Add aliases to the minimalized property names of the typedef,
|
||||||
* to improve readability.
|
* to improve readability.
|
||||||
|
@ -667,6 +709,113 @@ abstract SongTimeChange(RawSongTimeChange)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract ConductorTimeChange(RawConductorTimeChange)
|
||||||
|
{
|
||||||
|
public function new(timeStamp:Float, beatTime:Int, bpm:Float, timeSignatureNum:Int = 4, timeSignatureDen:Int = 4, beatTuplets:Array<Int>)
|
||||||
|
{
|
||||||
|
this = {
|
||||||
|
t: timeStamp,
|
||||||
|
b: beatTime,
|
||||||
|
bpm: bpm,
|
||||||
|
n: timeSignatureNum,
|
||||||
|
d: timeSignatureDen,
|
||||||
|
bt: beatTuplets,
|
||||||
|
st: 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var timeStamp(get, set):Float;
|
||||||
|
|
||||||
|
public function get_timeStamp():Float
|
||||||
|
{
|
||||||
|
return this.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_timeStamp(value:Float):Float
|
||||||
|
{
|
||||||
|
return this.t = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var beatTime(get, set):Int;
|
||||||
|
|
||||||
|
public function get_beatTime():Int
|
||||||
|
{
|
||||||
|
return this.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_beatTime(value:Int):Int
|
||||||
|
{
|
||||||
|
return this.b = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var bpm(get, set):Float;
|
||||||
|
|
||||||
|
public function get_bpm():Float
|
||||||
|
{
|
||||||
|
return this.bpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_bpm(value:Float):Float
|
||||||
|
{
|
||||||
|
return this.bpm = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var timeSignatureNum(get, set):Int;
|
||||||
|
|
||||||
|
public function get_timeSignatureNum():Int
|
||||||
|
{
|
||||||
|
return this.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_timeSignatureNum(value:Int):Int
|
||||||
|
{
|
||||||
|
return this.n = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var timeSignatureDen(get, set):Int;
|
||||||
|
|
||||||
|
public function get_timeSignatureDen():Int
|
||||||
|
{
|
||||||
|
return this.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_timeSignatureDen(value:Int):Int
|
||||||
|
{
|
||||||
|
return this.d = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var beatTuplets(get, set):Array<Int>;
|
||||||
|
|
||||||
|
public function get_beatTuplets():Array<Int>
|
||||||
|
{
|
||||||
|
if (Std.isOfType(this.bt, Int))
|
||||||
|
{
|
||||||
|
return [this.bt];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.bt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_beatTuplets(value:Array<Int>):Array<Int>
|
||||||
|
{
|
||||||
|
return this.bt = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var stepTime(get, set):Float;
|
||||||
|
|
||||||
|
public function get_stepTime():Float
|
||||||
|
{
|
||||||
|
return this.st;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_stepTime(value:Float):Float
|
||||||
|
{
|
||||||
|
return this.st = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum abstract SongTimeFormat(String) from String to String
|
enum abstract SongTimeFormat(String) from String to String
|
||||||
{
|
{
|
||||||
var TICKS = "ticks";
|
var TICKS = "ticks";
|
||||||
|
|
|
@ -5,6 +5,7 @@ import funkin.play.song.SongData.SongMetadata;
|
||||||
import funkin.play.song.SongData.SongPlayData;
|
import funkin.play.song.SongData.SongPlayData;
|
||||||
import funkin.play.song.SongData.SongTimeChange;
|
import funkin.play.song.SongData.SongTimeChange;
|
||||||
import funkin.play.song.SongData.SongTimeFormat;
|
import funkin.play.song.SongData.SongTimeFormat;
|
||||||
|
import funkin.util.Constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For SongMetadata and SongChartData objects,
|
* For SongMetadata and SongChartData objects,
|
||||||
|
@ -17,10 +18,16 @@ class SongValidator
|
||||||
public static final DEFAULT_TIMEFORMAT:SongTimeFormat = SongTimeFormat.MILLISECONDS;
|
public static final DEFAULT_TIMEFORMAT:SongTimeFormat = SongTimeFormat.MILLISECONDS;
|
||||||
public static final DEFAULT_DIVISIONS:Int = -1;
|
public static final DEFAULT_DIVISIONS:Int = -1;
|
||||||
public static final DEFAULT_LOOP:Bool = false;
|
public static final DEFAULT_LOOP:Bool = false;
|
||||||
public static final DEFAULT_GENERATEDBY:String = "Unknown";
|
|
||||||
public static final DEFAULT_STAGE:String = "mainStage";
|
public static final DEFAULT_STAGE:String = "mainStage";
|
||||||
public static final DEFAULT_SCROLLSPEED:Float = 1.0;
|
public static final DEFAULT_SCROLLSPEED:Float = 1.0;
|
||||||
|
|
||||||
|
public static var DEFAULT_GENERATEDBY(get, null):String;
|
||||||
|
|
||||||
|
static function get_DEFAULT_GENERATEDBY():String
|
||||||
|
{
|
||||||
|
return '${Constants.TITLE} - ${Constants.VERSION}';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the fields of a SongMetadata object (excluding the version field).
|
* Validates the fields of a SongMetadata object (excluding the version field).
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue