diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx index a0493869b..f83de069b 100644 --- a/source/funkin/Conductor.hx +++ b/source/funkin/Conductor.hx @@ -50,6 +50,16 @@ class Conductor // OLD, replaced with timeChanges. public static var bpmChangeMap:Array<BPMChangeEvent> = []; + /** + * Duration of a measure in milliseconds. Calculated based on bpm. + */ + public static var measureLengthMs(get, null):Float; + + static function get_measureLengthMs():Float + { + return crochet * timeSignatureNumerator; + } + /** * Duration of a beat in millisecond. Calculated based on bpm. */ diff --git a/source/funkin/CoolUtil.hx b/source/funkin/CoolUtil.hx index c7d3f7dab..82bf5201a 100644 --- a/source/funkin/CoolUtil.hx +++ b/source/funkin/CoolUtil.hx @@ -20,13 +20,6 @@ import openfl.filters.ShaderFilter; class CoolUtil { - public static var difficultyArray:Array<String> = ['EASY', "NORMAL", "HARD"]; - - public static function difficultyString():String - { - return difficultyArray[PlayState.storyDifficulty]; - } - public static function coolBaseLog(base:Float, fin:Float):Float { return Math.log(fin) / Math.log(base); @@ -119,8 +112,7 @@ class CoolUtil FlxTween.tween(screenWipeShit, {daAlphaShit: 1}, time, { ease: FlxEase.quadInOut, - onComplete: function(twn) - { + onComplete: function(twn) { screenShit.destroy(); FlxG.switchState(new MainMenuState()); } diff --git a/source/funkin/DialogueBox.hx b/source/funkin/DialogueBox.hx index e9c3587ad..4258f71ce 100644 --- a/source/funkin/DialogueBox.hx +++ b/source/funkin/DialogueBox.hx @@ -38,7 +38,7 @@ class DialogueBox extends FlxSpriteGroup { super(); - switch (PlayState.currentSong.song.toLowerCase()) + switch (PlayState.instance.currentSong.songId.toLowerCase()) { case 'senpai': FlxG.sound.playMusic(Paths.music('Lunchbox'), 0); @@ -53,8 +53,7 @@ class DialogueBox extends FlxSpriteGroup bgFade.alpha = 0; add(bgFade); - new FlxTimer().start(0.83, function(tmr:FlxTimer) - { + new FlxTimer().start(0.83, function(tmr:FlxTimer) { bgFade.alpha += (1 / 5) * 0.7; if (bgFade.alpha > 0.7) bgFade.alpha = 0.7; }, 5); @@ -80,7 +79,7 @@ class DialogueBox extends FlxSpriteGroup box = new FlxSprite(-20, 45); var hasDialog:Bool = false; - switch (PlayState.currentSong.song.toLowerCase()) + switch (PlayState.instance.currentSong.songId.toLowerCase()) { case 'senpai': hasDialog = true; @@ -152,8 +151,8 @@ class DialogueBox extends FlxSpriteGroup override function update(elapsed:Float):Void { // HARD CODING CUZ IM STUPDI - if (PlayState.currentSong.song.toLowerCase() == 'roses') portraitLeft.visible = false; - if (PlayState.currentSong.song.toLowerCase() == 'thorns') + if (PlayState.instance.currentSong.songId.toLowerCase() == 'roses') portraitLeft.visible = false; + if (PlayState.instance.currentSong.songId.toLowerCase() == 'thorns') { portraitLeft.color = FlxColor.BLACK; swagDialogue.color = FlxColor.WHITE; @@ -189,11 +188,10 @@ class DialogueBox extends FlxSpriteGroup { isEnding = true; - if (PlayState.currentSong.song.toLowerCase() == 'senpai' - || PlayState.currentSong.song.toLowerCase() == 'thorns') FlxG.sound.music.fadeOut(2.2, 0); + if (PlayState.instance.currentSong.songId.toLowerCase() == 'senpai' + || PlayState.instance.currentSong.songId.toLowerCase() == 'thorns') FlxG.sound.music.fadeOut(2.2, 0); - new FlxTimer().start(0.2, function(tmr:FlxTimer) - { + new FlxTimer().start(0.2, function(tmr:FlxTimer) { box.alpha -= 1 / 5; bgFade.alpha -= 1 / 5 * 0.7; portraitLeft.visible = false; @@ -203,8 +201,7 @@ class DialogueBox extends FlxSpriteGroup dropText.alpha = swagDialogue.alpha; }, 5); - new FlxTimer().start(1.2, function(tmr:FlxTimer) - { + new FlxTimer().start(1.2, function(tmr:FlxTimer) { finishThing(); kill(); }); @@ -233,8 +230,7 @@ class DialogueBox extends FlxSpriteGroup // swagDialogue.text = ; swagDialogue.resetText(dialogueList[0]); swagDialogue.start(0.04); - swagDialogue.completeCallback = function() - { + swagDialogue.completeCallback = function() { trace('dialogue finish'); handSelect.visible = true; dialogueEnded = true; diff --git a/source/funkin/FreeplayState.hx b/source/funkin/FreeplayState.hx index 2b869a21e..563c13c34 100644 --- a/source/funkin/FreeplayState.hx +++ b/source/funkin/FreeplayState.hx @@ -130,20 +130,26 @@ class FreeplayState extends MusicBeatSubState if (!FlxG.sound.music.playing) FlxG.sound.playMusic(Paths.music('freakyMenu')); } - if (StoryMenuState.weekUnlocked[2] || isDebug) addWeek(['Bopeebo', 'Fresh', 'Dadbattle'], 1, ['dad']); + // if (StoryMenuState.weekUnlocked[2] || isDebug) + addWeek(['Bopeebo', 'Fresh', 'Dadbattle'], 1, ['dad']); - if (StoryMenuState.weekUnlocked[2] || isDebug) addWeek(['Spookeez', 'South', 'Monster'], 2, ['spooky', 'spooky', 'monster']); + // if (StoryMenuState.weekUnlocked[2] || isDebug) + addWeek(['Spookeez', 'South', 'Monster'], 2, ['spooky', 'spooky', 'monster']); - if (StoryMenuState.weekUnlocked[3] || isDebug) addWeek(['Pico', 'Philly-Nice', 'Blammed'], 3, ['pico']); + // if (StoryMenuState.weekUnlocked[3] || isDebug) + addWeek(['Pico', 'Philly-Nice', 'Blammed'], 3, ['pico']); - if (StoryMenuState.weekUnlocked[4] || isDebug) addWeek(['Satin-Panties', 'High', 'MILF'], 4, ['mom']); + // if (StoryMenuState.weekUnlocked[4] || isDebug) + addWeek(['Satin-Panties', 'High', 'MILF'], 4, ['mom']); - if (StoryMenuState.weekUnlocked[5] || isDebug) addWeek(['Cocoa', 'Eggnog', 'Winter-Horrorland'], 5, - ['parents-christmas', 'parents-christmas', 'monster-christmas']); + // if (StoryMenuState.weekUnlocked[5] || isDebug) + addWeek(['Cocoa', 'Eggnog', 'Winter-Horrorland'], 5, ['parents-christmas', 'parents-christmas', 'monster-christmas']); - if (StoryMenuState.weekUnlocked[6] || isDebug) addWeek(['Senpai', 'Roses', 'Thorns'], 6, ['senpai', 'senpai', 'spirit']); + // if (StoryMenuState.weekUnlocked[6] || isDebug) + addWeek(['Senpai', 'Roses', 'Thorns'], 6, ['senpai', 'senpai', 'spirit']); - if (StoryMenuState.weekUnlocked[7] || isDebug) addWeek(['Ugh', 'Guns', 'Stress'], 7, ['tankman']); + // if (StoryMenuState.weekUnlocked[7] || isDebug) + addWeek(['Ugh', 'Guns', 'Stress'], 7, ['tankman']); addWeek(["Darnell", "lit-up", "2hot", "blazin"], 8, ['darnell']); diff --git a/source/funkin/GitarooPause.hx b/source/funkin/GitarooPause.hx index fda809548..5747de5e5 100644 --- a/source/funkin/GitarooPause.hx +++ b/source/funkin/GitarooPause.hx @@ -11,12 +11,16 @@ class GitarooPause extends MusicBeatState var replaySelect:Bool = false; - public function new():Void + var previousParams:PlayStateParams; + + public function new(previousParams:PlayStateParams):Void { super(); + + this.previousParams = previousParams; } - override function create() + override function create():Void { if (FlxG.sound.music != null) FlxG.sound.music.stop(); @@ -49,7 +53,7 @@ class GitarooPause extends MusicBeatState super.create(); } - override function update(elapsed:Float) + override function update(elapsed:Float):Void { if (controls.UI_LEFT_P || controls.UI_RIGHT_P) changeThing(); @@ -57,7 +61,7 @@ class GitarooPause extends MusicBeatState { if (replaySelect) { - FlxG.switchState(new PlayState()); + FlxG.switchState(new PlayState(previousParams)); } else { diff --git a/source/funkin/Highscore.hx b/source/funkin/Highscore.hx index 08ad7dcba..904d2cb45 100644 --- a/source/funkin/Highscore.hx +++ b/source/funkin/Highscore.hx @@ -39,7 +39,17 @@ class Highscore return false; } - public static function saveCompletion(song:String, completion:Float, ?diff:Int = 0):Bool + public static function saveScoreForDifficulty(song:String, score:Int = 0, diff:String = 'normal'):Bool + { + var diffInt:Int = 1; + + if (diff == 'easy') diffInt = 0; + else if (diff == 'hard') diffInt = 2; + + return saveScore(song, score, diffInt); + } + + public static function saveCompletion(song:String, completion:Float, diff:Int = 0):Bool { var formattedSong:String = formatSong(song, diff); @@ -57,20 +67,42 @@ class Highscore return false; } - public static function saveWeekScore(week:Int = 1, score:Int = 0, ?diff:Int = 0):Void + public static function saveCompletionForDifficulty(song:String, completion:Float, diff:String = 'normal'):Bool + { + var diffInt:Int = 1; + + if (diff == 'easy') diffInt = 0; + else if (diff == 'hard') diffInt = 2; + + return saveCompletion(song, completion, diffInt); + } + + public static function saveWeekScore(week:String, score:Int = 0, diff:Int = 0):Void { #if newgrounds - NGio.postScore(score, "Week " + week); + NGio.postScore(score, 'Campaign ID $week'); #end - var formattedSong:String = formatSong('week' + week, diff); + var formattedSong:String = formatSong(week, diff); if (songScores.exists(formattedSong)) { if (songScores.get(formattedSong) < score) setScore(formattedSong, score); } else + { setScore(formattedSong, score); + } + } + + public static function saveWeekScoreForDifficulty(week:String, score:Int = 0, diff:String = 'normal'):Void + { + var diffInt:Int = 1; + + if (diff == 'easy') diffInt = 0; + else if (diff == 'hard') diffInt = 2; + + saveWeekScore(week, score, diffInt); } static function setCompletion(formattedSong:String, completion:Float):Void @@ -122,7 +154,7 @@ class Highscore return songCompletion.get(formatSong(song, diff)); } - public static function getAllScores() + public static function getAllScores():Void { trace(songScores.toString()); } diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 76e85befd..8d7d2d550 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -237,20 +237,18 @@ class InitState extends FlxTransitionableState { var dif:Int = getDif(); - PlayState.currentSong = SongLoad.loadFromJson(song, song); - PlayState.currentSong_NEW = SongDataParser.fetchSong(song); - PlayState.isStoryMode = isStoryMode; - PlayState.storyDifficulty = dif; - PlayState.storyDifficulty_NEW = switch (dif) + var targetDifficulty = switch (dif) { case 0: 'easy'; case 1: 'normal'; case 2: 'hard'; default: 'normal'; }; - SongLoad.curDiff = PlayState.storyDifficulty_NEW; - PlayState.storyWeek = week; - LoadingState.loadAndSwitchState(new PlayState()); + LoadingState.loadAndSwitchState(new PlayState( + { + targetSong: SongDataParser.fetchSong(song), + targetDifficulty: targetDifficulty, + })); } } diff --git a/source/funkin/LoadingState.hx b/source/funkin/LoadingState.hx index dd5ff6040..604e78f79 100644 --- a/source/funkin/LoadingState.hx +++ b/source/funkin/LoadingState.hx @@ -1,5 +1,6 @@ package funkin; +import funkin.play.PlayStatePlaylist; import flixel.FlxSprite; import flixel.FlxState; import flixel.math.FlxMath; @@ -32,7 +33,7 @@ class LoadingState extends MusicBeatState this.stopMusic = stopMusic; } - override function create() + override function create():Void { var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, 0xFFcaff4d); add(bg); @@ -52,57 +53,56 @@ class LoadingState extends MusicBeatState initSongsManifest().onComplete(function(lib) { callbacks = new MultiCallback(onLoad); - var introComplete = callbacks.add("introComplete"); - checkLoadSong(getSongPath()); - if (PlayState.currentSong.needsVoices) - { - var files = PlayState.currentSong.voiceList; + var introComplete = callbacks.add('introComplete'); + // checkLoadSong(getSongPath()); + // if (PlayState.currentSong.needsVoices) + // { + // var files = PlayState.currentSong.voiceList; + // + // if (files == null) files = ['']; // loads with no file name assumption, to load 'Voices.ogg' or whatev normally + // + // for (sndFile in files) + // { + // checkLoadSong(getVocalPath(sndFile)); + // } + // } - if (files == null) files = [""]; // loads with no file name assumption, to load "Voices.ogg" or whatev normally + checkLibrary('shared'); + checkLibrary(PlayStatePlaylist.campaignId); + checkLibrary('tutorial'); - for (sndFile in files) - { - checkLoadSong(getVocalPath(sndFile)); - } - } - - checkLibrary("shared"); - if (PlayState.storyWeek > 0) checkLibrary("week" + PlayState.storyWeek); - else - checkLibrary("tutorial"); - - var fadeTime = 0.5; + var fadeTime:Float = 0.5; FlxG.camera.fade(FlxG.camera.bgColor, fadeTime, true); new FlxTimer().start(fadeTime + MIN_TIME, function(_) introComplete()); }); } - function checkLoadSong(path:String) + function checkLoadSong(path:String):Void { if (!Assets.cache.hasSound(path)) { - var library = Assets.getLibrary("songs"); - var symbolPath = path.split(":").pop(); + var library = Assets.getLibrary('songs'); + var symbolPath = path.split(':').pop(); // @:privateAccess // library.types.set(symbolPath, SOUND); // @:privateAccess // library.pathGroups.set(symbolPath, [library.__cacheBreak(symbolPath)]); - var callback = callbacks.add("song:" + path); + var callback = callbacks.add('song:' + path); Assets.loadSound(path).onComplete(function(_) { callback(); }); } } - function checkLibrary(library:String) + function checkLibrary(library:String):Void { trace(Assets.hasLibrary(library)); if (Assets.getLibrary(library) == null) { @:privateAccess - if (!LimeAssets.libraryPaths.exists(library)) throw "Missing library: " + library; + if (!LimeAssets.libraryPaths.exists(library)) throw 'Missing library: ' + library; - var callback = callbacks.add("library:" + library); + var callback = callbacks.add('library:' + library); Assets.loadLibrary(library).onComplete(function(_) { callback(); }); @@ -121,7 +121,7 @@ class LoadingState extends MusicBeatState var targetShit:Float = 0; - override function update(elapsed:Float) + override function update(elapsed:Float):Void { super.update(elapsed); @@ -147,44 +147,41 @@ class LoadingState extends MusicBeatState } #if debug - if (FlxG.keys.justPressed.SPACE) trace('fired: ' + callbacks.getFired() + " unfired:" + callbacks.getUnfired()); + if (FlxG.keys.justPressed.SPACE) trace('fired: ' + callbacks.getFired() + ' unfired:' + callbacks.getUnfired()); #end } - function onLoad() + function onLoad():Void { if (stopMusic && FlxG.sound.music != null) FlxG.sound.music.stop(); FlxG.switchState(target); } - static function getSongPath() + static function getSongPath():String { - return Paths.inst(PlayState.currentSong.song); + return Paths.inst(PlayState.instance.currentSong.songId); } - static function getVocalPath(?suffix:String) + inline static public function loadAndSwitchState(nextState:FlxState, shouldStopMusic = false):Void { - return Paths.voices(PlayState.currentSong.song, suffix); + FlxG.switchState(getNextState(nextState, shouldStopMusic)); } - inline static public function loadAndSwitchState(target:FlxState, stopMusic = false) + static function getNextState(nextState:FlxState, shouldStopMusic = false):FlxState { - FlxG.switchState(getNextState(target, stopMusic)); - } + Paths.setCurrentLevel(PlayStatePlaylist.campaignId); - static function getNextState(target:FlxState, stopMusic = false):FlxState - { #if NO_PRELOAD_ALL - var loaded = isSoundLoaded(getSongPath()) - && (!PlayState.currentSong.needsVoices || isSoundLoaded(getVocalPath())) - && isLibraryLoaded("shared"); - - if (!loaded) return new LoadingState(target, stopMusic); + // var loaded = isSoundLoaded(getSongPath()) + // && (!PlayState.currentSong.needsVoices || isSoundLoaded(getVocalPath())) + // && isLibraryLoaded('shared'); + // + if (true) return new LoadingState(nextState, shouldStopMusic); #end - if (stopMusic && FlxG.sound.music != null) FlxG.sound.music.stop(); + if (shouldStopMusic && FlxG.sound.music != null) FlxG.sound.music.stop(); - return target; + return nextState; } #if NO_PRELOAD_ALL @@ -199,16 +196,16 @@ class LoadingState extends MusicBeatState } #end - override function destroy() + override function destroy():Void { super.destroy(); callbacks = null; } - static function initSongsManifest() + static function initSongsManifest():Future<AssetLibrary> { - var id = "songs"; + var id = 'songs'; var promise = new Promise<AssetLibrary>(); var library = LimeAssets.getLibrary(id); @@ -230,10 +227,10 @@ class LoadingState extends MusicBeatState } else { - if (path.endsWith(".bundle")) + if (path.endsWith('.bundle')) { rootPath = path; - path += "/library.json"; + path += '/library.json'; } else { @@ -246,7 +243,7 @@ class LoadingState extends MusicBeatState AssetManifest.loadFromFile(path, rootPath).onComplete(function(manifest) { if (manifest == null) { - promise.error("Cannot parse asset manifest for library \"" + id + "\""); + promise.error('Cannot parse asset manifest for library \'' + id + '\''); return; } @@ -254,7 +251,7 @@ class LoadingState extends MusicBeatState if (library == null) { - promise.error("Cannot open library \"" + id + "\""); + promise.error('Cannot open library \'' + id + '\''); } else { @@ -264,7 +261,7 @@ class LoadingState extends MusicBeatState promise.completeWith(Future.withValue(library)); } }).onError(function(_) { - promise.error("There is no asset library with an ID of \"" + id + "\""); + promise.error('There is no asset library with an ID of \'' + id + '\''); }); return promise.future; @@ -287,7 +284,7 @@ class MultiCallback this.logId = logId; } - public function add(id = "untitled") + public function add(id = 'untitled'):Void->Void { id = '$length:$id'; length++; @@ -320,9 +317,9 @@ class MultiCallback if (logId != null) trace('$logId: $msg'); } - public function getFired() + public function getFired():Array<String> return fired.copy(); - public function getUnfired() + public function getUnfired():Array<Void->Void> return unfired.array(); } diff --git a/source/funkin/Note.hx b/source/funkin/Note.hx index 7fc49717e..4479774c5 100644 --- a/source/funkin/Note.hx +++ b/source/funkin/Note.hx @@ -1,5 +1,6 @@ package funkin; +import funkin.play.Strumline.StrumlineArrow; import flixel.FlxSprite; import flixel.math.FlxMath; import funkin.noteStuff.NoteBasic.NoteData; @@ -215,6 +216,24 @@ class Note extends FlxSprite } } + public function alignToSturmlineArrow(arrow:StrumlineArrow):Void + { + x = arrow.x; + + if (isSustainNote && prevNote != null) + { + if (prevNote.isSustainNote) + { + x = prevNote.x; + } + else + { + x += prevNote.width / 2; + x -= width / 2; + } + } + } + override function destroy() { prevNote = null; diff --git a/source/funkin/PauseSubState.hx b/source/funkin/PauseSubState.hx index 890b51cb7..7349052aa 100644 --- a/source/funkin/PauseSubState.hx +++ b/source/funkin/PauseSubState.hx @@ -1,9 +1,10 @@ package funkin; +import funkin.play.PlayStatePlaylist; import flixel.FlxSprite; import flixel.addons.transition.FlxTransitionableState; import flixel.group.FlxGroup.FlxTypedGroup; -import flixel.sound.FlxSound; +import flixel.system.FlxSound; import flixel.text.FlxText; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; @@ -20,9 +21,9 @@ class PauseSubState extends MusicBeatSubState 'Restart Song', 'Change Difficulty', 'Toggle Practice Mode', - 'Exit to menu' + 'Exit to Menu' ]; - var difficultyChoices:Array<String> = ['EASY', 'NORMAL', 'HARD', 'BACK']; + var difficultyChoices:Array<String> = ['EASY', 'NORMAL', 'HARD', 'ERECT', 'BACK']; var menuItems:Array<String> = []; var curSelected:Int = 0; @@ -41,10 +42,14 @@ class PauseSubState extends MusicBeatSubState menuItems = pauseOG; - if (PlayState.storyWeek == 6) // consistent with logic that decides asset lib!! + if (PlayStatePlaylist.campaignId == 'week6') + { pauseMusic = new FlxSound().loadEmbedded(Paths.music('breakfast-pixel'), true, true); + } else + { pauseMusic = new FlxSound().loadEmbedded(Paths.music('breakfast'), true, true); + } pauseMusic.volume = 0; pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2))); @@ -58,43 +63,38 @@ class PauseSubState extends MusicBeatSubState metaDataGrp = new FlxTypedGroup<FlxSprite>(); add(metaDataGrp); - var levelInfo:FlxText = new FlxText(20, 15, 0, "", 32); + var levelInfo:FlxText = new FlxText(20, 15, 0, '', 32); 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.setFormat(Paths.font("vcr.ttf"), 32); + levelInfo.setFormat(Paths.font('vcr.ttf'), 32); levelInfo.updateHitbox(); metaDataGrp.add(levelInfo); - var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, "", 32); - levelDifficulty.text += CoolUtil.difficultyString(); + var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, '', 32); + levelDifficulty.text += PlayState.instance.currentDifficulty.toTitleCase(); levelDifficulty.scrollFactor.set(); levelDifficulty.setFormat(Paths.font('vcr.ttf'), 32); levelDifficulty.updateHitbox(); metaDataGrp.add(levelDifficulty); - var deathCounter:FlxText = new FlxText(20, 15 + 64, 0, "", 32); - deathCounter.text = "Blue balled: " + PlayState.deathCounter; - deathCounter.text += "\n" + Highscore.tallies.totalNotesHit; - deathCounter.text += "\n" + Highscore.tallies.totalNotes; - deathCounter.text += "\n" + Std.string(Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes); + var deathCounter:FlxText = new FlxText(20, 15 + 64, 0, '', 32); + deathCounter.text = 'Blue balled: ${PlayState.instance.deathCounter}'; + FlxG.watch.addQuick('totalNotesHit', Highscore.tallies.totalNotesHit); + FlxG.watch.addQuick('totalNotes', Highscore.tallies.totalNotes); deathCounter.scrollFactor.set(); deathCounter.setFormat(Paths.font('vcr.ttf'), 32); deathCounter.updateHitbox(); metaDataGrp.add(deathCounter); - practiceText = new FlxText(20, 15 + 64 + 32, 0, "PRACTICE MODE", 32); + practiceText = new FlxText(20, 15 + 64 + 32, 0, 'PRACTICE MODE', 32); practiceText.scrollFactor.set(); practiceText.setFormat(Paths.font('vcr.ttf'), 32); practiceText.updateHitbox(); practiceText.x = FlxG.width - (practiceText.width + 20); - practiceText.visible = PlayState.isPracticeMode; + practiceText.visible = PlayState.instance.isPracticeMode; metaDataGrp.add(practiceText); levelDifficulty.alpha = 0; @@ -137,7 +137,7 @@ class PauseSubState extends MusicBeatSubState changeSelection(); } - override function update(elapsed:Float) + override function update(elapsed:Float):Void { if (pauseMusic.volume < 0.5) pauseMusic.volume += 0.01 * elapsed; @@ -180,41 +180,39 @@ class PauseSubState extends MusicBeatSubState { var daSelected:String = menuItems[curSelected]; + // TODO: Why is this based on the menu item's name? Make this an enum or something. switch (daSelected) { - case "Resume": + case 'Resume': close(); - case "EASY" | 'NORMAL' | "HARD": - 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(); - - PlayState.storyDifficulty = curSelected; - PlayState.storyDifficulty_NEW = daSelected.toLowerCase(); - - PlayState.needsReset = true; - - close(); - - case 'Toggle Practice Mode': - PlayState.isPracticeMode = !PlayState.isPracticeMode; - practiceText.visible = PlayState.isPracticeMode; case 'Change Difficulty': menuItems = difficultyChoices; regenMenu(); + + case 'EASY' | 'NORMAL' | 'HARD' | 'ERECT': + PlayState.instance.currentSong = SongDataParser.fetchSong(PlayState.instance.currentSong.songId.toLowerCase()); + + PlayState.instance.currentDifficulty = daSelected.toLowerCase(); + + PlayState.instance.needsReset = true; + + close(); case 'BACK': menuItems = pauseOG; regenMenu(); - case "Restart Song": - PlayState.needsReset = true; + case 'Toggle Practice Mode': + PlayState.instance.isPracticeMode = true; + practiceText.visible = PlayState.instance.isPracticeMode; + + case 'Restart Song': + PlayState.instance.needsReset = true; close(); - // FlxG.resetState(); - case "Exit to menu": + + case 'Exit to Menu': exitingToMenu = true; - PlayState.seenCutscene = false; - PlayState.deathCounter = 0; + PlayState.instance.deathCounter = 0; for (item in grpMenuShit.members) { @@ -225,7 +223,7 @@ class PauseSubState extends MusicBeatSubState FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransOut = true; - if (PlayState.isStoryMode) openSubState(new funkin.ui.StickerSubState(null, STORY)); + if (PlayStatePlaylist.isStoryMode) openSubState(new funkin.ui.StickerSubState(null, STORY)); else openSubState(new funkin.ui.StickerSubState()); } @@ -239,7 +237,7 @@ class PauseSubState extends MusicBeatSubState } } - override function destroy() + override function destroy():Void { pauseMusic.destroy(); @@ -260,12 +258,10 @@ class PauseSubState extends MusicBeatSubState item.targetY = index - curSelected; item.alpha = 0.6; - // item.setGraphicSize(Std.int(item.width * 0.8)); if (item.targetY == 0) { item.alpha = 1; - // item.setGraphicSize(Std.int(item.width)); } } } diff --git a/source/funkin/TitleState.hx b/source/funkin/TitleState.hx index e8e96e54d..b0ed157dd 100644 --- a/source/funkin/TitleState.hx +++ b/source/funkin/TitleState.hx @@ -84,8 +84,7 @@ class TitleState extends MusicBeatState */ // netConnection.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown); - new FlxTimer().start(1, function(tmr:FlxTimer) - { + new FlxTimer().start(1, function(tmr:FlxTimer) { startIntro(); }); } @@ -284,44 +283,6 @@ class TitleState extends MusicBeatState FlxTween.tween(FlxG.stage.window, {y: FlxG.stage.window.y + 100}, 0.7, {ease: FlxEase.quadInOut, type: PINGPONG}); } - /* - FlxG.watch.addQuick('cur display', FlxG.stage.window.display.id); - if (FlxG.keys.justPressed.Y) - { - // trace(FlxG.stage.window.display.name); - - if (FlxG.gamepads.firstActive != null) - { - trace(FlxG.gamepads.firstActive.model); - FlxG.gamepads.firstActive.id - } - else - trace('gamepad null'); - - // FlxG.stage.window.title = Std.string(FlxG.random.int(0, 20000)); - // FlxG.stage.window.setIcon(Image.fromFile('assets/images/icon16.png')); - // FlxG.stage.window.readPixels; - - if (FlxG.stage.window.width == Std.int(FlxG.stage.window.display.bounds.width)) - { - FlxG.stage.window.width = 1280; - FlxG.stage.window.height = 720; - FlxG.stage.window.y = 30; - } - else - { - FlxG.stage.window.width = Std.int(FlxG.stage.window.display.bounds.width); - FlxG.stage.window.height = Std.int(FlxG.stage.window.display.bounds.height); - FlxG.stage.window.x = Std.int(FlxG.stage.window.display.bounds.x); - FlxG.stage.window.y = Std.int(FlxG.stage.window.display.bounds.y); - } - } - */ - - #if debug - if (FlxG.keys.justPressed.EIGHT) FlxG.switchState(new CutsceneAnimTestState()); - #end - if (FlxG.sound.music != null) Conductor.songPosition = FlxG.sound.music.time; if (FlxG.keys.justPressed.F) FlxG.fullscreen = !FlxG.fullscreen; @@ -373,8 +334,7 @@ class TitleState extends MusicBeatState #if newgrounds if (!OutdatedSubState.leftState) { - NGio.checkVersion(function(version) - { + NGio.checkVersion(function(version) { // Check if version is outdated var localVersion:String = "v" + Application.current.meta.get('version'); var onlineVersion = version.split(" ")[0].trim(); @@ -391,8 +351,7 @@ class TitleState extends MusicBeatState }); } #end - new FlxTimer().start(2, function(tmr:FlxTimer) - { + new FlxTimer().start(2, function(tmr:FlxTimer) { // These assets are very unlikely to be used for the rest of gameplay, so it unloads them from cache/memory // Saves about 50mb of RAM or so??? Assets.cache.clear(Paths.image('gfDanceTitle')); diff --git a/source/funkin/play/Countdown.hx b/source/funkin/play/Countdown.hx index 0af098dbd..f7e072070 100644 --- a/source/funkin/play/Countdown.hx +++ b/source/funkin/play/Countdown.hx @@ -37,7 +37,7 @@ class Countdown // Stop any existing countdown. stopCountdown(); - PlayState.isInCountdown = true; + PlayState.instance.isInCountdown = true; Conductor.songPosition = Conductor.crochet * -5; // Handle onBeatHit events manually @:privateAccess @@ -46,8 +46,7 @@ class Countdown // The timer function gets called based on the beat of the song. countdownTimer = new FlxTimer(); - countdownTimer.start(Conductor.crochet / 1000, function(tmr:FlxTimer) - { + countdownTimer.start(Conductor.crochet / 1000, function(tmr:FlxTimer) { countdownStep = decrement(countdownStep); // Handle onBeatHit events manually @@ -216,8 +215,7 @@ class Countdown FlxTween.tween(countdownSprite, {y: countdownSprite.y += 100, alpha: 0}, Conductor.crochet / 1000, { ease: FlxEase.cubeInOut, - onComplete: function(twn:FlxTween) - { + onComplete: function(twn:FlxTween) { countdownSprite.destroy(); } }); diff --git a/source/funkin/play/GameOverSubstate.hx b/source/funkin/play/GameOverSubstate.hx index aa121ac36..f0694c818 100644 --- a/source/funkin/play/GameOverSubstate.hx +++ b/source/funkin/play/GameOverSubstate.hx @@ -153,11 +153,9 @@ class GameOverSubState extends MusicBeatSubState // KEYBOARD ONLY: Return to the menu when pressing the assigned key. if (controls.BACK) { - PlayState.deathCounter = 0; - PlayState.seenCutscene = false; gameOverMusic.stop(); - if (PlayState.isStoryMode) FlxG.switchState(new StoryMenuState()); + if (PlayStatePlaylist.isStoryMode) FlxG.switchState(new StoryMenuState()); else FlxG.switchState(new FreeplayState()); } @@ -171,11 +169,11 @@ class GameOverSubState extends MusicBeatSubState else { // Music hasn't started yet. - switch (PlayState.storyWeek) + switch (PlayStatePlaylist.campaignId) { // TODO: Make the behavior for playing Jeff's voicelines generic or un-hardcoded. // This will simplify the class and make it easier for mods to add death quotes. - case 7: + case "week7": if (boyfriend.getCurrentAnimation().startsWith('firstDeath') && boyfriend.isAnimationFinished() && !playingJeffQuote) { playingJeffQuote = true; @@ -214,7 +212,7 @@ class GameOverSubState extends MusicBeatSubState FlxG.camera.fade(FlxColor.BLACK, 2, false, function() { // ...close the GameOverSubState. FlxG.camera.fade(FlxColor.BLACK, 1, true, null, true); - PlayState.needsReset = true; + PlayState.instance.needsReset = true; // Readd Boyfriend to the stage. boyfriend.isDead = false; diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index adcc509c5..bac61d854 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1,5 +1,6 @@ package funkin.play; +import funkin.ui.story.StoryMenuState; import flixel.addons.display.FlxPieDial; import flixel.addons.transition.FlxTransitionableState; import flixel.FlxCamera; @@ -969,10 +970,10 @@ class PlayState extends MusicBeatState oldNote = newNote; // Generate X sustain notes. - var sustainSections = Math.round(songNote.length / Conductor.stepLengthMs); + var sustainSections = Math.round(songNote.length / Conductor.stepCrochet); for (noteIndex in 0...sustainSections) { - var noteTimeOffset:Float = Conductor.stepLengthMs + (Conductor.stepLengthMs * noteIndex); + 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; @@ -1573,7 +1574,7 @@ class PlayState extends MusicBeatState Highscore.saveWeekScoreForDifficulty(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignScore, currentDifficulty); } - FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; + // FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; FlxG.save.flush(); moveToResultsScreen(); @@ -2213,7 +2214,7 @@ class PlayState extends MusicBeatState var frameShit:Float = (1 / 24) * 2; // equals 2 frames in the animation - new FlxTimer().start(((Conductor.beatLengthMs / 1000) * 1.25) - frameShit, function(tmr) { + new FlxTimer().start(((Conductor.crochet / 1000) * 1.25) - frameShit, function(tmr) { animShit.forceFinish(); }); } diff --git a/source/funkin/play/PlayStatePlaylist.hx b/source/funkin/play/PlayStatePlaylist.hx new file mode 100644 index 000000000..acfd26752 --- /dev/null +++ b/source/funkin/play/PlayStatePlaylist.hx @@ -0,0 +1,56 @@ +package funkin.play; + +import funkin.util.Constants; + +/** + * Manages playback of multiple songs in a row. + * + * TODO: Add getters/setters for all these properties to validate them. + */ +class PlayStatePlaylist +{ + /** + * Whether the game is currently in Story Mode. If false, we are in Free Play Mode. + */ + public static var isStoryMode(default, default):Bool = false; + + /** + * The loist of upcoming songs to be played. + * When the user completes a song in Story Mode, the first entry in this list is played. + * When this list is empty, move to the Results screen instead. + */ + public static var playlistSongIds:Array<String> = []; + + /** + * The cumulative score for all the songs in the playlist. + */ + public static var campaignScore:Int = 0; + + /** + * The title of this playlist, for example `Week 4` or `Weekend 1` + */ + public static var campaignTitle:String = 'UNKNOWN'; + + /** + * The internal ID of the current playlist, for example `week4` or `weekend-1`. + */ + public static var campaignId:String = 'unknown'; + + /** + * The current difficulty selected for this level (as a named ID). + */ + public static var currentDifficulty(default, default):String = Constants.DEFAULT_DIFFICULTY; + + /** + * Resets the playlist to its default state. + */ + public static function reset():Void + { + isStoryMode = false; + playlistSongIds = []; + campaignScore = 0; + campaignTitle = 'UNKNOWN'; + campaignId = 'unknown'; + currentDifficulty = Constants.DEFAULT_DIFFICULTY; + } +} diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 6b9167846..12be46fc8 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -118,16 +118,16 @@ class ResultState extends MusicBeatSubState difficulty = new FlxSprite(555); - var diffSpr:String = switch (CoolUtil.difficultyString()) + var diffSpr:String = switch (PlayState.instance.currentDifficulty) { - case "EASY": - "difEasy"; - case "NORMAL": - "difNormal"; - case "HARD": - "difHard"; + case 'EASY': + 'difEasy'; + case 'NORMAL': + 'difNormal'; + case 'HARD': + 'difHard'; case _: - "difNormal"; + 'difNormal'; } difficulty.loadGraphic(Paths.image("resultScreen/" + diffSpr)); @@ -144,7 +144,7 @@ class ResultState extends MusicBeatSubState } else { - songName.text += PlayState.currentSong.song; + songName.text += PlayState.instance.currentSong.songId; } songName.antialiasing = true; diff --git a/source/funkin/play/event/ZoomCameraSongEvent.hx b/source/funkin/play/event/ZoomCameraSongEvent.hx index bceeb251a..e6e9c843d 100644 --- a/source/funkin/play/event/ZoomCameraSongEvent.hx +++ b/source/funkin/play/event/ZoomCameraSongEvent.hx @@ -76,8 +76,7 @@ class ZoomCameraSongEvent extends SongEvent return; } - FlxTween.tween(PlayState.instance, {defaultCameraZoom: zoom * FlxCamera.defaultZoom}, (Conductor.stepLengthMs * duration / 1000), - {ease: easeFunction}); + FlxTween.tween(PlayState.instance, {defaultCameraZoom: zoom * FlxCamera.defaultZoom}, (Conductor.stepCrochet * duration / 1000), {ease: easeFunction}); } } diff --git a/source/funkin/ui/stageBuildShit/StageOffsetSubstate.hx b/source/funkin/ui/stageBuildShit/StageOffsetSubstate.hx index f6b9cae3d..c757ce72e 100644 --- a/source/funkin/ui/stageBuildShit/StageOffsetSubstate.hx +++ b/source/funkin/ui/stageBuildShit/StageOffsetSubstate.hx @@ -260,7 +260,7 @@ class StageOffsetSubState extends HaxeUISubState // if (uiStuff != null) remove(uiStuff); // uiStuff = null; - PlayState.disableKeys = false; + PlayState.instance.disableKeys = false; PlayState.instance.resetCamera(); FlxG.mouse.visible = false; close(); diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index fadc7bbee..2ff0c0235 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -13,6 +13,8 @@ import funkin.data.level.LevelRegistry; import funkin.modding.events.ScriptEvent; import funkin.modding.events.ScriptEventDispatcher; import funkin.play.PlayState; +import funkin.play.PlayStatePlaylist; +import funkin.play.song.Song; import funkin.play.song.SongData.SongDataParser; import funkin.util.Constants; @@ -474,26 +476,25 @@ class StoryMenuState extends MusicBeatState prop.playConfirm(); } - PlayState.storyPlaylist = currentLevel.getSongs(); - PlayState.isStoryMode = true; - - PlayState.currentSong = SongLoad.loadFromJson(PlayState.storyPlaylist[0].toLowerCase(), PlayState.storyPlaylist[0].toLowerCase()); - PlayState.currentSong_NEW = SongDataParser.fetchSong(PlayState.storyPlaylist[0].toLowerCase()); - Paths.setCurrentLevel(currentLevel.id); - // TODO: Fix this. - PlayState.storyWeek = 0; - PlayState.campaignScore = 0; + PlayStatePlaylist.playlistSongIds = currentLevel.getSongs(); + PlayStatePlaylist.isStoryMode = true; + PlayStatePlaylist.campaignScore = 0; - // TODO: Fix this. - PlayState.storyDifficulty = 0; - PlayState.storyDifficulty_NEW = currentDifficultyId; + var targetSongId:String = PlayStatePlaylist.playlistSongIds.shift(); - SongLoad.curDiff = PlayState.storyDifficulty_NEW; + var targetSong:Song = SongDataParser.fetchSong(targetSongId); + + PlayStatePlaylist.campaignId = currentLevel.id; + PlayStatePlaylist.campaignTitle = currentLevel.getTitle(); new FlxTimer().start(1, function(tmr:FlxTimer) { - LoadingState.loadAndSwitchState(new PlayState(), true); + LoadingState.loadAndSwitchState(new PlayState( + { + targetSong: targetSong, + targetDifficulty: currentDifficultyId, + }), true); }); }