diff --git a/assets/preload/images/storymenu/week6.png b/assets/preload/images/storymenu/week6.png index 8a45fb5..fca67f0 100644 Binary files a/assets/preload/images/storymenu/week6.png and b/assets/preload/images/storymenu/week6.png differ diff --git a/docs/changelogs/changelog-1.5.3.md b/docs/changelogs/changelog-1.5.3.md new file mode 100644 index 0000000..510ff5b --- /dev/null +++ b/docs/changelogs/changelog-1.5.3.md @@ -0,0 +1,16 @@ +# Latest (master) changelog + +Changes marked with 💖 will be listed in the short version of the changelog in `version.downloadMe`. + +### Additions +- Score Screen (💖) +- Show your highest combo in the freeplay menu +- New asset loading system (💖) +- New Logo (💖) + +### Changes +- Rewrote the entire hit ranking system (💖) + +### Bugfixes +- NPS not showing if accuracy is disabled +- Fixed song names so they don't crash (💖) diff --git a/docs/changelogs/index.md b/docs/changelogs/index.md index aa2dca3..38dc1b7 100644 --- a/docs/changelogs/index.md +++ b/docs/changelogs/index.md @@ -1,6 +1,7 @@ # Changelogs - [Latest](latest) (Contains changes that are not in a release yet) +- [1.5.3](changelog-1.5.3) - [1.5.2](changelog-1.5.2) - [1.5.1](changelog-1.5.1) - [1.5.0](changelog-1.5.0) diff --git a/docs/changelogs/latest.md b/docs/changelogs/latest.md index d7def91..5d6ee6f 100644 --- a/docs/changelogs/latest.md +++ b/docs/changelogs/latest.md @@ -3,10 +3,10 @@ Changes marked with 💖 will be listed in the short version of the changelog in `version.downloadMe`. ### Additions -- Nothing here yet! +- Nothing yet! ### Changes -- Nothing here yet! +- Nothing yet! ### Bugfixes -- Nothing here yet! +- Nothing yet! \ No newline at end of file diff --git a/source/CoolUtil.hx b/source/CoolUtil.hx index 92cc2c0..24dc749 100644 --- a/source/CoolUtil.hx +++ b/source/CoolUtil.hx @@ -6,11 +6,11 @@ using StringTools; class CoolUtil { - public static var difficultyArray:Array = ['EASY', "NORMAL", "HARD"]; + public static var difficultyArray:Array = ['Easy', "Normal", "Hard"]; - public static function difficultyString():String + public static function difficultyFromInt(difficulty:Int):String { - return difficultyArray[PlayState.storyDifficulty]; + return difficultyArray[difficulty]; } public static function coolTextFile(path:String):Array diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index d58f3f3..7a3be07 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -253,15 +253,7 @@ class FreeplayState extends MusicBeatState combo = Highscore.getCombo(songHighscore, curDifficulty); #end - switch (curDifficulty) - { - case 0: - diffText.text = "EASY"; - case 1: - diffText.text = 'NORMAL'; - case 2: - diffText.text = "HARD"; - } + diffText.text = CoolUtil.difficultyFromInt(curDifficulty).toUpperCase(); } function changeSelection(change:Int = 0) diff --git a/source/HelperFunctions.hx b/source/HelperFunctions.hx index 8f6c6fc..b17dc6a 100644 --- a/source/HelperFunctions.hx +++ b/source/HelperFunctions.hx @@ -1,3 +1,5 @@ +import flixel.math.FlxMath; + class HelperFunctions { public static function truncateFloat( number : Float, precision : Int): Float { @@ -6,4 +8,8 @@ class HelperFunctions num = Math.round( num ) / Math.pow(10, precision); return num; } + + public static function GCD(a, b) { + return b == 0 ? FlxMath.absInt(a) : GCD(b, a % b); + } } \ No newline at end of file diff --git a/source/HitGraph.hx b/source/HitGraph.hx new file mode 100644 index 0000000..e3b3790 --- /dev/null +++ b/source/HitGraph.hx @@ -0,0 +1,250 @@ +import openfl.display.Bitmap; +import openfl.display.BitmapData; +import openfl.text.TextFieldAutoSize; +import flixel.system.FlxAssets; +import openfl.text.TextFormat; +import flash.display.Graphics; +import flash.display.Shape; +import flash.display.Sprite; +import flash.text.TextField; +import flash.text.TextFormatAlign; +import flixel.math.FlxMath; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; + +/** + * stolen from https://github.com/HaxeFlixel/flixel/blob/master/flixel/system/debug/stats/StatsGraph.hx + */ +class HitGraph extends Sprite +{ + static inline var AXIS_COLOR:FlxColor = 0xffffff; + static inline var AXIS_ALPHA:Float = 0.5; + inline static var HISTORY_MAX:Int = 30; + + public var minLabel:TextField; + public var curLabel:TextField; + public var maxLabel:TextField; + public var avgLabel:TextField; + + public var minValue:Float = -(Math.floor((PlayState.rep.replay.sf / 60) * 1000) + 95); + public var maxValue:Float = Math.floor((PlayState.rep.replay.sf / 60) * 1000) + 95; + + public var graphColor:FlxColor; + + public var history:Array = []; + + public var bitmap:Bitmap; + + var _axis:Shape; + var _width:Int; + var _height:Int; + var _unit:String; + var _labelWidth:Int; + var _label:String; + + public function new(X:Int, Y:Int, Width:Int, Height:Int) + { + super(); + x = X; + y = Y; + _width = Width; + _height = Height; + + var bm = new BitmapData(Width,Height); + bm.draw(this); + bitmap = new Bitmap(bm); + + _axis = new Shape(); + _axis.x = _labelWidth + 10; + + var ts = Math.floor((PlayState.rep.replay.sf / 60) * 1000) / 166; + + var early = createTextField(10,10,FlxColor.WHITE,12); + var late = createTextField(10,_height - 20,FlxColor.WHITE,12); + + early.text = "Early (" + -166 * ts + "ms)"; + late.text = "Late (" + 166 * ts + "ms)"; + + addChild(early); + addChild(late); + + addChild(_axis); + + drawAxes(); + } + + /** + * Redraws the axes of the graph. + */ + function drawAxes():Void + { + var gfx = _axis.graphics; + gfx.clear(); + gfx.lineStyle(1, AXIS_COLOR, AXIS_ALPHA); + + // y-Axis + gfx.moveTo(0, 0); + gfx.lineTo(0, _height); + + // x-Axis + gfx.moveTo(0, _height); + gfx.lineTo(_width, _height); + + gfx.moveTo(0, _height / 2); + gfx.lineTo(_width, _height / 2); + + } + + public static function createTextField(X:Float = 0, Y:Float = 0, Color:FlxColor = FlxColor.WHITE, Size:Int = 12):TextField + { + return initTextField(new TextField(), X, Y, Color, Size); + } + + public static function initTextField(tf:T, X:Float = 0, Y:Float = 0, Color:FlxColor = FlxColor.WHITE, Size:Int = 12):T + { + tf.x = X; + tf.y = Y; + tf.multiline = false; + tf.wordWrap = false; + tf.embedFonts = true; + tf.selectable = false; + #if flash + tf.antiAliasType = AntiAliasType.NORMAL; + tf.gridFitType = GridFitType.PIXEL; + #end + tf.defaultTextFormat = new TextFormat("assets/fonts/vcr.ttf", Size, Color.to24Bit()); + tf.alpha = Color.alphaFloat; + tf.autoSize = TextFieldAutoSize.LEFT; + return tf; + } + + function drawJudgementLine(ms:Float):Void + { + + var gfx:Graphics = graphics; + + gfx.lineStyle(1, graphColor, 0.3); + + var ts = Math.floor((PlayState.rep.replay.sf / 60) * 1000) / 166; + var range:Float = Math.max(maxValue - minValue, maxValue * 0.1); + + var value = ((ms * ts) - minValue) / range; + + var pointY = _axis.y + ((-value * _height - 1) + _height); + + var graphX = _axis.x + 1; + + if (ms == 45) + gfx.moveTo(graphX, _axis.y + pointY); + + var graphX = _axis.x + 1; + + gfx.drawRect(graphX,pointY, _width,1); + + gfx.lineStyle(1, graphColor, 1); + } + + /** + * Redraws the graph based on the values stored in the history. + */ + function drawGraph():Void + { + var gfx:Graphics = graphics; + gfx.clear(); + gfx.lineStyle(1, graphColor, 1); + + gfx.beginFill(0x00FF00); + drawJudgementLine(45); + gfx.endFill(); + + gfx.beginFill(0xFF0000); + drawJudgementLine(90); + gfx.endFill(); + + gfx.beginFill(0x8b0000); + drawJudgementLine(135); + gfx.endFill(); + + gfx.beginFill(0x580000); + drawJudgementLine(166); + gfx.endFill(); + + gfx.beginFill(0x00FF00); + drawJudgementLine(-45); + gfx.endFill(); + + gfx.beginFill(0xFF0000); + drawJudgementLine(-90); + gfx.endFill(); + + gfx.beginFill(0x8b0000); + drawJudgementLine(-135); + gfx.endFill(); + + gfx.beginFill(0x580000); + drawJudgementLine(-166); + gfx.endFill(); + + + var inc:Float = _width / (PlayState.rep.replay.songNotes.length); + var range:Float = Math.max(maxValue - minValue, maxValue * 0.1); + var graphX = _axis.x + 1; + + for (i in 0...history.length) + { + + var value = (history[i][0] - minValue) / range; + var judge = history[i][1]; + + switch(judge) + { + case "sick": + gfx.beginFill(0x00FFFF); + case "good": + gfx.beginFill(0x00FF00); + case "bad": + gfx.beginFill(0xFF0000); + case "shit": + gfx.beginFill(0x8b0000); + case "miss": + gfx.beginFill(0x580000); + default: + gfx.beginFill(0xFFFFFF); + } + var pointY = (-value * _height - 1) + _height; + /*if (i == 0) + gfx.moveTo(graphX, _axis.y + pointY);*/ + gfx.drawRect(graphX + (i * inc), pointY,4,4); + + gfx.endFill(); + } + + var bm = new BitmapData(_width,_height); + bm.draw(this); + bitmap = new Bitmap(bm); + } + + public function addToHistory(diff:Float, judge:String) + { + history.push([diff,judge]); + } + + public function update():Void + { + drawGraph(); + } + + public function average():Float + { + var sum:Float = 0; + for (value in history) + sum += value; + return sum / history.length; + } + + public function destroy():Void + { + _axis = FlxDestroyUtil.removeChild(this, _axis); + history = null; + } +} \ No newline at end of file diff --git a/source/KadeEngineData.hx b/source/KadeEngineData.hx index b5f65f4..37841d2 100644 --- a/source/KadeEngineData.hx +++ b/source/KadeEngineData.hx @@ -87,6 +87,9 @@ class KadeEngineData if (FlxG.save.data.camzoom == null) FlxG.save.data.camzoom = true; + if (FlxG.save.data.scoreScreen == null) + FlxG.save.data.scoreScreen = true; + Conductor.recalculateTimings(); PlayerSettings.player1.controls.loadKeyBinds(); KeyBinds.keyCheck(); diff --git a/source/LoadReplayState.hx b/source/LoadReplayState.hx index afcdfd4..3560888 100644 --- a/source/LoadReplayState.hx +++ b/source/LoadReplayState.hx @@ -54,7 +54,7 @@ class LoadReplayState extends MusicBeatState var string:String = controlsStrings[i]; actualNames[i] = string; var rep:Replay = Replay.LoadReplay(string); - controlsStrings[i] = string.split("time")[0] + " " + (rep.replay.songDiff == 2 ? "HARD" : rep.replay.songDiff == 1 ? "EASY" : "NORMAL"); + controlsStrings[i] = string.split("time")[0] + " " + CoolUtil.difficultyFromInt(rep.replay.songDiff).toUpperCase(); } if (controlsStrings.length == 0) @@ -148,23 +148,32 @@ class LoadReplayState extends MusicBeatState PlayState.loadRep = true; - // adjusting the song name to be compatible - var songFormat = StringTools.replace(PlayState.rep.replay.songName, " ", "-"); - switch (songFormat) { - case 'Dad-Battle': songFormat = 'Dadbattle'; - case 'Philly-Nice': songFormat = 'Philly'; - // Replay v1.0 support - case 'dad-battle': songFormat = 'Dadbattle'; - case 'philly-nice': songFormat = 'Philly'; + if (PlayState.rep.replay.replayGameVer == Replay.version) + { + + // adjusting the song name to be compatible + var songFormat = StringTools.replace(PlayState.rep.replay.songName, " ", "-"); + switch (songFormat) { + case 'Dad-Battle': songFormat = 'Dadbattle'; + case 'Philly-Nice': songFormat = 'Philly'; + // Replay v1.0 support + case 'dad-battle': songFormat = 'Dadbattle'; + case 'philly-nice': songFormat = 'Philly'; + } + + var poop:String = Highscore.formatSong(songFormat, PlayState.rep.replay.songDiff); + + PlayState.SONG = Song.loadFromJson(poop, PlayState.rep.replay.songName); + PlayState.isStoryMode = false; + PlayState.storyDifficulty = PlayState.rep.replay.songDiff; + PlayState.storyWeek = getWeekNumbFromSong(PlayState.rep.replay.songName); + LoadingState.loadAndSwitchState(new PlayState()); + } + else + { + PlayState.rep = null; + PlayState.loadRep = false; } - - var poop:String = Highscore.formatSong(songFormat, PlayState.rep.replay.songDiff); - - PlayState.SONG = Song.loadFromJson(poop, PlayState.rep.replay.songName); - PlayState.isStoryMode = false; - PlayState.storyDifficulty = PlayState.rep.replay.songDiff; - PlayState.storyWeek = getWeekNumbFromSong(PlayState.rep.replay.songName); - LoadingState.loadAndSwitchState(new PlayState()); } } @@ -187,7 +196,7 @@ class LoadReplayState extends MusicBeatState var rep:Replay = Replay.LoadReplay(actualNames[curSelected]); - poggerDetails.text = "Replay Details - \nDate Created: " + rep.replay.timestamp + "\nSong: " + rep.replay.songName + "\nReplay Version: " + rep.replay.replayGameVer + ' (' + (rep.replay.replayGameVer != Replay.version ? "OUTDATED but still usable" : "Latest") + ')\n'; + poggerDetails.text = "Replay Details - \nDate Created: " + rep.replay.timestamp + "\nSong: " + rep.replay.songName + "\nReplay Version: " + rep.replay.replayGameVer + ' (' + (rep.replay.replayGameVer != Replay.version ? "OUTDATED not useable!" : "Latest") + ')\n'; // selector.y = (70 * curSelected) + 30; diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx index 2815cfd..f2c5d67 100644 --- a/source/MainMenuState.hx +++ b/source/MainMenuState.hx @@ -39,7 +39,7 @@ class MainMenuState extends MusicBeatState public static var nightly:String = ""; - public static var kadeEngineVer:String = "1.5.2" + nightly; + public static var kadeEngineVer:String = "1.5.3" + nightly; public static var gameVer:String = "0.2.7.1"; var magenta:FlxSprite; @@ -165,7 +165,7 @@ class MainMenuState extends MusicBeatState { if (optionShit[curSelected] == 'donate') { - fancyOpenURL("https://www.kickstarter.com/projects/funkin/friday-night-funkin-the-full-ass-game"); + fancyOpenURL("https://ninja-muffin24.itch.io/funkin"); } else { diff --git a/source/ModchartState.hx b/source/ModchartState.hx index 5483b99..6e194d1 100644 --- a/source/ModchartState.hx +++ b/source/ModchartState.hx @@ -437,8 +437,6 @@ class ModchartState PlayState.instance.removeObject(sprite); return true; }); - - // hud/camera @@ -461,6 +459,14 @@ class ModchartState GlobalVideo.get().restart(); }); + Lua_helper.add_callback(lua,"getVideoSpriteX", function() { + return PlayState.instance.videoSprite.x; + }); + + Lua_helper.add_callback(lua,"getVideoSpriteY", function() { + return PlayState.instance.videoSprite.y; + }); + Lua_helper.add_callback(lua,"setVideoSpritePos", function(x:Int,y:Int) { PlayState.instance.videoSprite.setPosition(x,y); }); diff --git a/source/Note.hx b/source/Note.hx index 1eb3977..f7f915e 100644 --- a/source/Note.hx +++ b/source/Note.hx @@ -50,7 +50,7 @@ class Note extends FlxSprite x += 50; // MAKE SURE ITS DEFINITELY OFF SCREEN? y -= 2000; - this.strumTime = strumTime; + this.strumTime = Math.round(strumTime); if (this.strumTime < 0 ) this.strumTime = 0; diff --git a/source/Options.hx b/source/Options.hx index 6077498..d5e82c2 100644 --- a/source/Options.hx +++ b/source/Options.hx @@ -296,8 +296,8 @@ class Judgement extends Option override function getValue():String { return "Safe Frames: " + Conductor.safeFrames + - " - SIK: " + HelperFunctions.truncateFloat(45 * Conductor.timeScale, 0) + - "ms GD: " + HelperFunctions.truncateFloat(90 * Conductor.timeScale, 0) + + " - SIK: " + HelperFunctions.truncateFloat(22 * Conductor.timeScale, 0) + + "ms GD: " + HelperFunctions.truncateFloat(45 * Conductor.timeScale, 0) + "ms BD: " + HelperFunctions.truncateFloat(135 * Conductor.timeScale, 0) + "ms SHT: " + HelperFunctions.truncateFloat(155 * Conductor.timeScale, 0) + "ms TOTAL: " + HelperFunctions.truncateFloat(Conductor.safeZoneOffset,0) + "ms"; @@ -338,6 +338,27 @@ class FPSOption extends Option } } +class ScoreScreen extends Option +{ + public function new(desc:String) + { + super(); + description = desc; + } + + public override function press():Bool + { + FlxG.save.data.scoreScreen = !FlxG.save.data.scoreScreen; + return true; + } + + private override function updateDisplay():String + { + return (FlxG.save.data.scoreScreen ? "Show Score Screen" : "No Score Screen"); + } +} + + class FPSCapOption extends Option diff --git a/source/OptionsMenu.hx b/source/OptionsMenu.hx index a55c1c7..f5d8830 100644 --- a/source/OptionsMenu.hx +++ b/source/OptionsMenu.hx @@ -58,6 +58,7 @@ class OptionsMenu extends MusicBeatState new FlashingLightsOption("Toggle flashing lights that can cause epileptic seizures and strain."), new WatermarkOption("Enable and disable all watermarks from the engine."), new BotPlay("Showcase your charts and mods with autoplay.") + new ScoreScreen("Show the score screen after the end of a song") ]), new OptionCategory("Manage Save Data", [ diff --git a/source/PauseSubState.hx b/source/PauseSubState.hx index ab9b1a2..3985d4b 100644 --- a/source/PauseSubState.hx +++ b/source/PauseSubState.hx @@ -33,6 +33,13 @@ class PauseSubState extends MusicBeatSubstate { super(); + if (PlayState.instance.useVideo) + { + menuItems.remove("Resume"); + if (GlobalVideo.get().playing) + GlobalVideo.get().pause(); + } + pauseMusic = new FlxSound().loadEmbedded(Paths.music('breakfast'), true, true); pauseMusic.volume = 0; pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2))); @@ -52,7 +59,7 @@ class PauseSubState extends MusicBeatSubstate add(levelInfo); var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, "", 32); - levelDifficulty.text += CoolUtil.difficultyString(); + levelDifficulty.text += CoolUtil.difficultyFromInt(PlayState.storyDifficulty).toUpperCase(); levelDifficulty.scrollFactor.set(); levelDifficulty.setFormat(Paths.font('vcr.ttf'), 32); levelDifficulty.updateHitbox(); @@ -98,6 +105,9 @@ class PauseSubState extends MusicBeatSubstate super.update(elapsed); + if (PlayState.instance.useVideo) + menuItems.remove('Resume'); + var upP = controls.UP_P; var downP = controls.DOWN_P; var leftP = controls.LEFT_P; @@ -187,8 +197,20 @@ class PauseSubState extends MusicBeatSubstate case "Resume": close(); case "Restart Song": + if (PlayState.instance.useVideo) + { + GlobalVideo.get().stop(); + PlayState.instance.remove(PlayState.instance.videoSprite); + PlayState.instance.removedVideo = true; + } FlxG.resetState(); case "Exit to menu": + if (PlayState.instance.useVideo) + { + GlobalVideo.get().stop(); + PlayState.instance.remove(PlayState.instance.videoSprite); + PlayState.instance.removedVideo = true; + } if(PlayState.loadRep) { FlxG.save.data.botplay = false; diff --git a/source/PlayState.hx b/source/PlayState.hx index 1228ba8..32cffe9 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -76,6 +76,7 @@ class PlayState extends MusicBeatState public static var storyPlaylist:Array = []; public static var storyDifficulty:Int = 1; public static var weekSong:Int = 0; + public static var weekScore:Int = 0; public static var shits:Int = 0; public static var bads:Int = 0; public static var goods:Int = 0; @@ -104,6 +105,8 @@ class PlayState extends MusicBeatState private var vocals:FlxSound; + public var originalX:Float; + public static var dad:Character; public static var gf:Character; public static var boyfriend:Boyfriend; @@ -129,7 +132,8 @@ class PlayState extends MusicBeatState public var health:Float = 1; //making public because sethealth doesnt work without it private var combo:Int = 0; public static var misses:Int = 0; - private var accuracy:Float = 0.00; + public static var campaignMisses:Int = 0; + public var accuracy:Float = 0.00; private var accuracyDefault:Float = 0.00; private var totalNotesHit:Float = 0; private var totalNotesHitDefault:Float = 0; @@ -177,7 +181,7 @@ class PlayState extends MusicBeatState var wiggleShit:WiggleEffect = new WiggleEffect(); var talking:Bool = true; - var songScore:Int = 0; + public var songScore:Int = 0; var songScoreDef:Int = 0; var scoreTxt:FlxText; var replayTxt:FlxText; @@ -207,7 +211,9 @@ class PlayState extends MusicBeatState // BotPlay text private var botPlayState:FlxText; // Replay shit - private var saveNotes:Array = []; + private var saveNotes:Array = []; + + public static var highestCombo:Int = 0; private var executeModchart = false; @@ -227,16 +233,25 @@ class PlayState extends MusicBeatState if (FlxG.sound.music != null) FlxG.sound.music.stop(); - sicks = 0; - bads = 0; - shits = 0; - goods = 0; - + if (!isStoryMode) + { + sicks = 0; + bads = 0; + shits = 0; + goods = 0; + } misses = 0; repPresses = 0; repReleases = 0; + + PlayStateChangeables.useDownscroll = FlxG.save.data.downscroll; + PlayStateChangeables.safeFrames = FlxG.save.data.frames; + PlayStateChangeables.scrollSpeed = FlxG.save.data.scrollSpeed; + PlayStateChangeables.botPlay = FlxG.save.data.botplay; + + // pre lowercasing the song name (create) var songLowercase = StringTools.replace(PlayState.SONG.song, " ", "-").toLowerCase(); switch (songLowercase) { @@ -244,6 +259,8 @@ class PlayState extends MusicBeatState case 'philly-nice': songLowercase = 'philly'; } + removedVideo = false; + #if windows executeModchart = FileSystem.exists(Paths.lua(songLowercase + "/modchart")); #end @@ -255,15 +272,7 @@ class PlayState extends MusicBeatState #if windows // Making difficulty text for Discord Rich Presence. - switch (storyDifficulty) - { - case 0: - storyDifficultyText = "Easy"; - case 1: - storyDifficultyText = "Normal"; - case 2: - storyDifficultyText = "Hard"; - } + storyDifficultyText = CoolUtil.difficultyFromInt(storyDifficulty); iconRPC = SONG.player2; @@ -315,7 +324,7 @@ class PlayState extends MusicBeatState Conductor.mapBPMChanges(SONG); Conductor.changeBPM(SONG.bpm); - trace('INFORMATION ABOUT WHAT U PLAYIN WIT:\nFRAMES: ' + Conductor.safeFrames + '\nZONE: ' + Conductor.safeZoneOffset + '\nTS: ' + Conductor.timeScale + '\nBotPlay : ' + FlxG.save.data.botplay); + trace('INFORMATION ABOUT WHAT U PLAYIN WIT:\nFRAMES: ' + PlayStateChangeables.safeFrames + '\nZONE: ' + Conductor.safeZoneOffset + '\nTS: ' + Conductor.timeScale + '\nBotPlay : ' + PlayStateChangeables.botPlay); //dialogue shit switch (songLowercase) @@ -865,13 +874,17 @@ class PlayState extends MusicBeatState { FlxG.watch.addQuick('rep rpesses',repPresses); FlxG.watch.addQuick('rep releases',repReleases); - - FlxG.save.data.botplay = true; - FlxG.save.data.scrollSpeed = rep.replay.noteSpeed; - FlxG.save.data.downscroll = rep.replay.isDownscroll; // FlxG.watch.addQuick('Queued',inputsQueued); + + PlayStateChangeables.useDownscroll = rep.replay.isDownscroll; + PlayStateChangeables.safeFrames = rep.replay.sf; + PlayStateChangeables.botPlay = true; } + trace('uh ' + PlayStateChangeables.safeFrames); + + trace("SF CALC: " + Math.floor((PlayStateChangeables.safeFrames / 60) * 1000)); + var doof:DialogueBox = new DialogueBox(false, dialogue); // doof.x += 70; // doof.y = FlxG.height * 0.5; @@ -883,7 +896,7 @@ class PlayState extends MusicBeatState strumLine = new FlxSprite(0, 50).makeGraphic(FlxG.width, 10); strumLine.scrollFactor.set(); - if (FlxG.save.data.downscroll) + if (PlayStateChangeables.useDownscroll) strumLine.y = FlxG.height - 165; strumLineNotes = new FlxTypedGroup(); @@ -929,7 +942,7 @@ class PlayState extends MusicBeatState if (FlxG.save.data.songPosition) // I dont wanna talk about this code :( { songPosBG = new FlxSprite(0, 10).loadGraphic(Paths.image('healthBar')); - if (FlxG.save.data.downscroll) + if (PlayStateChangeables.useDownscroll) songPosBG.y = FlxG.height * 0.9 + 45; songPosBG.screenCenter(X); songPosBG.scrollFactor.set(); @@ -941,8 +954,8 @@ class PlayState extends MusicBeatState songPosBar.createFilledBar(FlxColor.GRAY, FlxColor.LIME); add(songPosBar); - var songName = new FlxText(songPosBG.x + (songPosBG.width / 2) - 20,songPosBG.y,0,SONG.song, 16); - if (FlxG.save.data.downscroll) + var songName = new FlxText(songPosBG.x + (songPosBG.width / 2) - (SONG.song.length * 5),songPosBG.y,0,SONG.song, 16); + if (PlayStateChangeables.useDownscroll) songName.y -= 3; songName.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); songName.scrollFactor.set(); @@ -951,7 +964,7 @@ class PlayState extends MusicBeatState } healthBarBG = new FlxSprite(0, FlxG.height * 0.9).loadGraphic(Paths.image('healthBar')); - if (FlxG.save.data.downscroll) + if (PlayStateChangeables.useDownscroll) healthBarBG.y = 50; healthBarBG.screenCenter(X); healthBarBG.scrollFactor.set(); @@ -965,37 +978,43 @@ class PlayState extends MusicBeatState add(healthBar); // Add Kade Engine watermark - kadeEngineWatermark = new FlxText(4,healthBarBG.y + 50,0,SONG.song + " " + (storyDifficulty == 2 ? "Hard" : storyDifficulty == 1 ? "Normal" : "Easy") + (Main.watermarks ? " - KE " + MainMenuState.kadeEngineVer : ""), 16); + kadeEngineWatermark = new FlxText(4,healthBarBG.y + 50,0,SONG.song + " " + CoolUtil.difficultyFromInt(storyDifficulty) + (Main.watermarks ? " - KE " + MainMenuState.kadeEngineVer : ""), 16); kadeEngineWatermark.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); kadeEngineWatermark.scrollFactor.set(); add(kadeEngineWatermark); - if (FlxG.save.data.downscroll) + if (PlayStateChangeables.useDownscroll) kadeEngineWatermark.y = FlxG.height * 0.9 + 45; scoreTxt = new FlxText(FlxG.width / 2 - 235, healthBarBG.y + 50, 0, "", 20); - if (!FlxG.save.data.accuracyDisplay) - scoreTxt.x = healthBarBG.x + healthBarBG.width / 2; - scoreTxt.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, CENTER, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); + + scoreTxt.screenCenter(X); + + originalX = scoreTxt.x; + + scoreTxt.scrollFactor.set(); - if (offsetTesting) - scoreTxt.x += 300; - if(FlxG.save.data.botplay) scoreTxt.x = FlxG.width / 2 - 20; + + scoreTxt.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, FlxTextAlign.CENTER, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); + add(scoreTxt); - replayTxt = new FlxText(healthBarBG.x + healthBarBG.width / 2 - 75, healthBarBG.y + (FlxG.save.data.downscroll ? 100 : -100), 0, "REPLAY", 20); + replayTxt = new FlxText(healthBarBG.x + healthBarBG.width / 2 - 75, healthBarBG.y + (PlayStateChangeables.useDownscroll ? 100 : -100), 0, "REPLAY", 20); replayTxt.setFormat(Paths.font("vcr.ttf"), 42, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); + replayTxt.borderSize = 4; + replayTxt.borderQuality = 2; replayTxt.scrollFactor.set(); if (loadRep) { add(replayTxt); } // Literally copy-paste of the above, fu - botPlayState = new FlxText(healthBarBG.x + healthBarBG.width / 2 - 75, healthBarBG.y + (FlxG.save.data.downscroll ? 100 : -100), 0, "BOTPLAY", 20); + botPlayState = new FlxText(healthBarBG.x + healthBarBG.width / 2 - 75, healthBarBG.y + (PlayStateChangeables.useDownscroll ? 100 : -100), 0, "BOTPLAY", 20); botPlayState.setFormat(Paths.font("vcr.ttf"), 42, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); botPlayState.scrollFactor.set(); - - if(FlxG.save.data.botplay && !loadRep) add(botPlayState); + botPlayState.borderSize = 4; + botPlayState.borderQuality = 2; + if(PlayStateChangeables.botPlay && !loadRep) add(botPlayState); iconP1 = new HealthIcon(SONG.player1, true); iconP1.y = healthBar.y - (iconP1.height / 2); @@ -1341,7 +1360,7 @@ class PlayState extends MusicBeatState remove(songName); songPosBG = new FlxSprite(0, 10).loadGraphic(Paths.image('healthBar')); - if (FlxG.save.data.downscroll) + if (PlayStateChangeables.useDownscroll) songPosBG.y = FlxG.height * 0.9 + 45; songPosBG.screenCenter(X); songPosBG.scrollFactor.set(); @@ -1354,8 +1373,8 @@ class PlayState extends MusicBeatState songPosBar.createFilledBar(FlxColor.GRAY, FlxColor.LIME); add(songPosBar); - var songName = new FlxText(songPosBG.x + (songPosBG.width / 2) - 20,songPosBG.y,0,SONG.song, 16); - if (FlxG.save.data.downscroll) + var songName = new FlxText(songPosBG.x + (songPosBG.width / 2) - (SONG.song.length * 5),songPosBG.y,0,SONG.song, 16); + if (PlayStateChangeables.useDownscroll) songName.y -= 3; songName.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE,FlxColor.BLACK); songName.scrollFactor.set(); @@ -1754,7 +1773,7 @@ class PlayState extends MusicBeatState perfectMode = false; #end - if (FlxG.save.data.botplay && FlxG.keys.justPressed.ONE) + if (PlayStateChangeables.botPlay && FlxG.keys.justPressed.ONE) camHUD.visible = !camHUD.visible; @@ -1763,6 +1782,8 @@ class PlayState extends MusicBeatState if (GlobalVideo.get().ended && !removedVideo) { remove(videoSprite); + FlxG.stage.window.onFocusOut.remove(focusOut); + FlxG.stage.window.onFocusIn.remove(focusIn); removedVideo = true; } } @@ -1872,6 +1893,10 @@ class PlayState extends MusicBeatState scoreTxt.text = Ratings.CalculateRanking(songScore,songScoreDef,nps,maxNPS,accuracy); + var lengthInPx = scoreTxt.textField.length * scoreTxt.frameHeight; // bad way but does more or less a better job + + scoreTxt.x = (originalX - (lengthInPx / 2)) + 335; + if (FlxG.keys.justPressed.ENTER && startedCountdown && canPause) { persistentUpdate = false; @@ -1894,6 +1919,8 @@ class PlayState extends MusicBeatState { GlobalVideo.get().stop(); remove(videoSprite); + FlxG.stage.window.onFocusOut.remove(focusOut); + FlxG.stage.window.onFocusIn.remove(focusIn); removedVideo = true; } #if windows @@ -1945,6 +1972,8 @@ class PlayState extends MusicBeatState { GlobalVideo.get().stop(); remove(videoSprite); + FlxG.stage.window.onFocusOut.remove(focusOut); + FlxG.stage.window.onFocusIn.remove(focusIn); removedVideo = true; } @@ -2295,12 +2324,12 @@ class PlayState extends MusicBeatState if (!daNote.modifiedByLua) { - if (FlxG.save.data.downscroll) + if (PlayStateChangeables.useDownscroll) { if (daNote.mustPress) - daNote.y = (playerStrums.members[Math.floor(Math.abs(daNote.noteData))].y + 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(FlxG.save.data.scrollSpeed == 1 ? SONG.speed : FlxG.save.data.scrollSpeed, 2)); + daNote.y = (playerStrums.members[Math.floor(Math.abs(daNote.noteData))].y + 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(PlayStateChangeables.scrollSpeed == 1 ? SONG.speed : PlayStateChangeables.scrollSpeed, 2)); else - daNote.y = (strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].y + 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(FlxG.save.data.scrollSpeed == 1 ? SONG.speed : FlxG.save.data.scrollSpeed, 2)); + daNote.y = (strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].y + 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(PlayStateChangeables.scrollSpeed == 1 ? SONG.speed : PlayStateChangeables.scrollSpeed, 2)); if(daNote.isSustainNote) { // Remember = minus makes notes go up, plus makes them go down @@ -2310,7 +2339,7 @@ class PlayState extends MusicBeatState daNote.y += daNote.height / 2; // If not in botplay, only clip sustain notes when properly hit, botplay gets to clip it everytime - if(!FlxG.save.data.botplay) + if(!PlayStateChangeables.botPlay) { if((!daNote.mustPress || daNote.wasGoodHit || daNote.prevNote.wasGoodHit && !daNote.canBeHit) && daNote.y - daNote.offset.y * daNote.scale.y + daNote.height >= (strumLine.y + Note.swagWidth / 2)) { @@ -2332,14 +2361,14 @@ class PlayState extends MusicBeatState }else { if (daNote.mustPress) - daNote.y = (playerStrums.members[Math.floor(Math.abs(daNote.noteData))].y - 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(FlxG.save.data.scrollSpeed == 1 ? SONG.speed : FlxG.save.data.scrollSpeed, 2)); + daNote.y = (playerStrums.members[Math.floor(Math.abs(daNote.noteData))].y - 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(PlayStateChangeables.scrollSpeed == 1 ? SONG.speed : PlayStateChangeables.scrollSpeed, 2)); else - daNote.y = (strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].y - 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(FlxG.save.data.scrollSpeed == 1 ? SONG.speed : FlxG.save.data.scrollSpeed, 2)); + daNote.y = (strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].y - 0.45 * (Conductor.songPosition - daNote.strumTime) * FlxMath.roundDecimal(PlayStateChangeables.scrollSpeed == 1 ? SONG.speed : PlayStateChangeables.scrollSpeed, 2)); if(daNote.isSustainNote) { daNote.y -= daNote.height / 2; - if(!FlxG.save.data.botplay) + if(!PlayStateChangeables.botPlay) { if((!daNote.mustPress || daNote.wasGoodHit || daNote.prevNote.wasGoodHit && !daNote.canBeHit) && daNote.y + daNote.offset.y * daNote.scale.y <= (strumLine.y + Note.swagWidth / 2)) { @@ -2451,7 +2480,7 @@ class PlayState extends MusicBeatState // WIP interpolation shit? Need to fix the pause issue // daNote.y = (strumLine.y - (songTime - daNote.strumTime) * (0.45 * PlayState.SONG.speed)); - if ((daNote.mustPress && daNote.tooLate && !FlxG.save.data.downscroll || daNote.mustPress && daNote.tooLate && FlxG.save.data.downscroll) && daNote.mustPress) + if ((daNote.mustPress && daNote.tooLate && !PlayStateChangeables.useDownscroll || daNote.mustPress && daNote.tooLate && PlayStateChangeables.useDownscroll) && daNote.mustPress) { if (daNote.isSustainNote && daNote.wasGoodHit) { @@ -2460,10 +2489,26 @@ class PlayState extends MusicBeatState } else { - health -= 0.075; - vocals.volume = 0; - if (theFunne) - noteMiss(daNote.noteData, daNote); + if (loadRep && daNote.isSustainNote) + { + // im tired and lazy this sucks I know i'm dumb + if (findByTime(daNote.strumTime) != null) + totalNotesHit += 1; + else + { + health -= 0.075; + vocals.volume = 0; + if (theFunne) + noteMiss(daNote.noteData, daNote); + } + } + else + { + health -= 0.075; + vocals.volume = 0; + if (theFunne) + noteMiss(daNote.noteData, daNote); + } } daNote.visible = false; @@ -2501,16 +2546,21 @@ class PlayState extends MusicBeatState if (useVideo) { GlobalVideo.get().stop(); + FlxG.stage.window.onFocusOut.remove(focusOut); + FlxG.stage.window.onFocusIn.remove(focusIn); PlayState.instance.remove(PlayState.instance.videoSprite); } + if (isStoryMode) + campaignMisses = misses; + if (!loadRep) rep.SaveReplay(saveNotes); else { - FlxG.save.data.botplay = false; - FlxG.save.data.scrollSpeed = 1; - FlxG.save.data.downscroll = false; + PlayStateChangeables.botPlay = false; + PlayStateChangeables.scrollSpeed = 1; + PlayStateChangeables.useDownscroll = false; } if (FlxG.save.data.fpsCap > 290) @@ -2527,6 +2577,8 @@ class PlayState extends MusicBeatState canPause = false; FlxG.sound.music.volume = 0; vocals.volume = 0; + FlxG.sound.music.pause(); + vocals.pause(); if (SONG.validScore) { // adjusting the highscore song name to be compatible @@ -2560,12 +2612,20 @@ class PlayState extends MusicBeatState if (storyPlaylist.length <= 0) { - FlxG.sound.playMusic(Paths.music('freakyMenu')); - transIn = FlxTransitionableState.defaultTransIn; transOut = FlxTransitionableState.defaultTransOut; - FlxG.switchState(new StoryMenuState()); + paused = true; + + FlxG.sound.music.stop(); + vocals.stop(); + if (FlxG.save.data.scoreScreen) + openSubState(new ResultsScreen()); + else + { + FlxG.sound.playMusic(Paths.music('freakyMenu')); + FlxG.switchState(new MainMenuState()); + } #if windows if (luaModchart != null) @@ -2623,7 +2683,17 @@ class PlayState extends MusicBeatState else { trace('WENT BACK TO FREEPLAY??'); - FlxG.switchState(new FreeplayState()); + + paused = true; + + + FlxG.sound.music.stop(); + vocals.stop(); + + if (FlxG.save.data.scoreScreen) + openSubState(new ResultsScreen()); + else + FlxG.switchState(new PlayState()); } } } @@ -2639,11 +2709,10 @@ class PlayState extends MusicBeatState private function popUpScore(daNote:Note):Void { - var noteDiff:Float = Math.abs(Conductor.songPosition - daNote.strumTime); - var wife:Float = EtternaFunctions.wife3(noteDiff, Conductor.timeScale); + var noteDiff:Float = -(daNote.strumTime - Conductor.songPosition); + var wife:Float = EtternaFunctions.wife3(-noteDiff, Conductor.timeScale); // boyfriend.playAnim('hey'); vocals.volume = 1; - var placement:String = Std.string(combo); var coolText:FlxText = new FlxText(0, 0, 0, placement, 32); @@ -2738,7 +2807,10 @@ class PlayState extends MusicBeatState rating.velocity.x -= FlxG.random.int(0, 10); var msTiming = HelperFunctions.truncateFloat(noteDiff, 3); - if(FlxG.save.data.botplay) msTiming = 0; + if(PlayStateChangeables.botPlay && !loadRep) msTiming = 0; + + if (loadRep) + msTiming = HelperFunctions.truncateFloat(findByTime(daNote.strumTime)[3], 3); if (currentTimingShown != null) remove(currentTimingShown); @@ -2784,7 +2856,7 @@ class PlayState extends MusicBeatState if (currentTimingShown.alpha != 1) currentTimingShown.alpha = 1; - if(!FlxG.save.data.botplay) add(currentTimingShown); + if(!PlayStateChangeables.botPlay || loadRep) add(currentTimingShown); var comboSpr:FlxSprite = new FlxSprite().loadGraphic(Paths.image(pixelShitPart1 + 'combo' + pixelShitPart2)); comboSpr.screenCenter(); @@ -2801,7 +2873,7 @@ class PlayState extends MusicBeatState comboSpr.velocity.x += FlxG.random.int(1, 10); currentTimingShown.velocity.x += comboSpr.velocity.x; - if(!FlxG.save.data.botplay) add(rating); + if(!PlayStateChangeables.botPlay || loadRep) add(rating); if (!curStage.startsWith('school')) { @@ -2828,6 +2900,9 @@ class PlayState extends MusicBeatState var comboSplit:Array = (combo + "").split(''); + if (combo > highestCombo) + highestCombo = combo; + // make sure we have 3 digits to display (looks weird otherwise lol) if (comboSplit.length == 1) { @@ -2952,7 +3027,7 @@ class PlayState extends MusicBeatState #end // Prevent player input if botplay is on - if(FlxG.save.data.botplay) + if(PlayStateChangeables.botPlay) { holdArray = [false, false, false, false]; pressArray = [false, false, false, false]; @@ -3012,8 +3087,6 @@ class PlayState extends MusicBeatState } }); - trace('\nCURRENT LINE:\n' + directionsAccounted); - for (note in dumbNotes) { FlxG.log.add("killing dumb ass note at " + note.strumTime); @@ -3062,7 +3135,7 @@ class PlayState extends MusicBeatState noteMiss(shit, null); } - if(dontCheck && possibleNotes.length > 0 && FlxG.save.data.ghost && !FlxG.save.data.botplay) + if(dontCheck && possibleNotes.length > 0 && FlxG.save.data.ghost && !PlayStateChangeables.botPlay) { if (mashViolations > 8) { @@ -3078,17 +3151,19 @@ class PlayState extends MusicBeatState notes.forEachAlive(function(daNote:Note) { - if(FlxG.save.data.downscroll && daNote.y > strumLine.y || - !FlxG.save.data.downscroll && daNote.y < strumLine.y) + if(PlayStateChangeables.useDownscroll && daNote.y > strumLine.y || + !PlayStateChangeables.useDownscroll && daNote.y < strumLine.y) { // Force good note hit regardless if it's too late to hit it or not as a fail safe - if(FlxG.save.data.botplay && daNote.canBeHit && daNote.mustPress || - FlxG.save.data.botplay && daNote.tooLate && daNote.mustPress) + if(PlayStateChangeables.botPlay && daNote.canBeHit && daNote.mustPress || + PlayStateChangeables.botPlay && daNote.tooLate && daNote.mustPress) { if(loadRep) { //trace('ReplayNote ' + tmpRepNote.strumtime + ' | ' + tmpRepNote.direction); - if(rep.replay.songNotes.contains(HelperFunctions.truncateFloat(daNote.strumTime, 2))) + var n = findByTime(daNote.strumTime); + trace(n); + if(n != null) { goodNoteHit(daNote); boyfriend.holdTimer = daNote.sustainLength; @@ -3101,7 +3176,7 @@ class PlayState extends MusicBeatState } }); - if (boyfriend.holdTimer > Conductor.stepCrochet * 4 * 0.001 && (!holdArray.contains(true) || FlxG.save.data.botplay)) + if (boyfriend.holdTimer > Conductor.stepCrochet * 4 * 0.001 && (!holdArray.contains(true) || PlayStateChangeables.botPlay)) { if (boyfriend.animation.curAnim.name.startsWith('sing') && !boyfriend.animation.curAnim.name.endsWith('miss')) boyfriend.playAnim('idle'); @@ -3125,6 +3200,17 @@ class PlayState extends MusicBeatState }); } + public function findByTime(time:Float):Array + { + for (i in rep.replay.songNotes) + { + //trace('checking ' + Math.round(i[0]) + ' against ' + Math.round(time)); + if (i[0] == time) + return i; + } + return null; + } + public var fuckingVolume:Float = 1; public var useVideo = false; @@ -3134,10 +3220,34 @@ class PlayState extends MusicBeatState public var videoSprite:FlxSprite; + public function focusOut() { + if (paused) + return; + persistentUpdate = false; + persistentDraw = true; + paused = true; + + if (FlxG.sound.music != null) + { + FlxG.sound.music.pause(); + vocals.pause(); + } + + openSubState(new PauseSubState(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y)); + } + public function focusIn() + { + // nada + } + + public function backgroundVideo(source:String) // for background videos { useVideo = true; + FlxG.stage.window.onFocusOut.add(focusOut); + FlxG.stage.window.onFocusIn.add(focusIn); + var ourSource:String = "assets/videos/daWeirdVid/dontDelete.webm"; WebmPlayer.SKIP_STEP_LIMIT = 90; var str1:String = "WEBM SHIT"; @@ -3173,7 +3283,7 @@ class PlayState extends MusicBeatState remove(boyfriend); remove(dad); add(videoSprite); - add(gf); + add(gf); add(boyfriend); add(dad); @@ -3197,6 +3307,15 @@ class PlayState extends MusicBeatState combo = 0; misses++; + if (daNote != null) + { + if (!loadRep) + saveNotes.push([daNote.strumTime,0,direction,166 * Math.floor((PlayState.rep.replay.sf / 60) * 1000) / 166]); + } + else + if (!loadRep) + saveNotes.push([Conductor.songPosition,0,direction,166 * Math.floor((PlayState.rep.replay.sf / 60) * 1000) / 166]); + //var noteDiff:Float = Math.abs(daNote.strumTime - Conductor.songPosition); //var wife:Float = EtternaFunctions.wife3(noteDiff, FlxG.save.data.etternaMode ? 1 : 1.7); @@ -3283,9 +3402,9 @@ class PlayState extends MusicBeatState function noteCheck(controlArray:Array, note:Note):Void // sorry lol { - var noteDiff:Float = Math.abs(note.strumTime - Conductor.songPosition); + var noteDiff:Float = -(note.strumTime - Conductor.songPosition); - note.rating = Ratings.CalculateRating(noteDiff); + note.rating = Ratings.CalculateRating(noteDiff, Math.floor((PlayStateChangeables.safeFrames / 60) * 1000)); /* if (loadRep) { @@ -3334,10 +3453,16 @@ class PlayState extends MusicBeatState if (mashing != 0) mashing = 0; - var noteDiff:Float = Math.abs(note.strumTime - Conductor.songPosition); + var noteDiff:Float = -(note.strumTime - Conductor.songPosition); + + if(loadRep) + noteDiff = findByTime(note.strumTime)[3]; note.rating = Ratings.CalculateRating(noteDiff); + if (note.rating == "miss") + return; + // add newest note to front of notesHitArray // the oldest notes are at the end and are removed first if (!note.isSustainNote) @@ -3379,7 +3504,13 @@ class PlayState extends MusicBeatState if(!loadRep && note.mustPress) - saveNotes.push(HelperFunctions.truncateFloat(note.strumTime, 2)); + { + var array = [note.strumTime,note.sustainLength,note.noteData,noteDiff]; + if (note.isSustainNote) + array[1] = -1; + trace('pushing ' + array[0]); + saveNotes.push(array); + } playerStrums.forEach(function(spr:FlxSprite) { @@ -3518,8 +3649,6 @@ class PlayState extends MusicBeatState } #end - - // yes this updates every step. // yes this is bad // but i'm doing it to update misses and accuracy @@ -3542,7 +3671,7 @@ class PlayState extends MusicBeatState if (generatedMusic) { - notes.sort(FlxSort.byY, (FlxG.save.data.downscroll ? FlxSort.ASCENDING : FlxSort.DESCENDING)); + notes.sort(FlxSort.byY, (PlayStateChangeables.useDownscroll ? FlxSort.ASCENDING : FlxSort.DESCENDING)); } #if windows @@ -3592,13 +3721,14 @@ class PlayState extends MusicBeatState camHUD.zoom += 0.03; } - iconP1.setGraphicSize(Std.int(iconP1.width + 30)); - iconP2.setGraphicSize(Std.int(iconP2.width + 30)); - - iconP1.updateHitbox(); - iconP2.updateHitbox(); } + iconP1.setGraphicSize(Std.int(iconP1.width + 30)); + iconP2.setGraphicSize(Std.int(iconP2.width + 30)); + + iconP1.updateHitbox(); + iconP2.updateHitbox(); + if (curBeat % gfSpeed == 0) { gf.dance(); diff --git a/source/PlayStateChangeables.hx b/source/PlayStateChangeables.hx new file mode 100644 index 0000000..8ee4995 --- /dev/null +++ b/source/PlayStateChangeables.hx @@ -0,0 +1,7 @@ +class PlayStateChangeables +{ + public static var useDownscroll:Bool; + public static var safeFrames:Int; + public static var scrollSpeed:Float; + public static var botPlay:Bool; +} \ No newline at end of file diff --git a/source/Ratings.hx b/source/Ratings.hx index 45dca20..92b0ee5 100644 --- a/source/Ratings.hx +++ b/source/Ratings.hx @@ -5,7 +5,7 @@ class Ratings public static function GenerateLetterRank(accuracy:Float) // generate a letter ranking { var ranking:String = "N/A"; - if(FlxG.save.data.botplay) + if(FlxG.save.data.botplay && !PlayState.loadRep) ranking = "BotPlay"; if (PlayState.misses == 0 && PlayState.bads == 0 && PlayState.shits == 0 && PlayState.goods == 0) // Marvelous (SICK) Full Combo @@ -86,7 +86,7 @@ class Ratings if (accuracy == 0) ranking = "N/A"; - else if(FlxG.save.data.botplay) + else if(FlxG.save.data.botplay && !PlayState.loadRep) ranking = "BotPlay"; return ranking; @@ -107,37 +107,45 @@ class Ratings // trace('Hit Info\nDifference: ' + noteDiff + '\nZone: ' + Conductor.safeZoneOffset * 1.5 + "\nTS: " + customTimeScale + "\nLate: " + 155 * customTimeScale); - if (FlxG.save.data.botplay) - return "good"; // FUNNY - - if (noteDiff > 166 * customTimeScale) // so god damn early its a miss - return "miss"; - if (noteDiff > 135 * customTimeScale) // way early - return "shit"; - else if (noteDiff > 90 * customTimeScale) // early - return "bad"; - else if (noteDiff > 45 * customTimeScale) // your kinda there - return "good"; - else if (noteDiff < -45 * customTimeScale) // little late - return "good"; - else if (noteDiff < -90 * customTimeScale) // late - return "bad"; - else if (noteDiff < -135 * customTimeScale) // late as fuck - return "shit"; - else if (noteDiff < -166 * customTimeScale) // so god damn late its a miss - return "miss"; - return "sick"; + if (FlxG.save.data.botplay && !PlayState.loadRep) + return "sick"; // FUNNY + + + var rating = checkRating(noteDiff,customTimeScale); + + + return rating; + } + + public static function checkRating(ms:Float, ts:Float) + { + var rating = "miss"; + if (ms < 166 * ts && ms > 135 * ts) + rating = "shit"; + if (ms > -166 * ts && ms < -135 * ts) + rating = "shit"; + if (ms < 135 * ts && ms > 90 * ts) + rating = "bad"; + if (ms > -135 * ts && ms < -90 * ts) + rating = "bad"; + if (ms < 90 * ts && ms > 45 * ts) + rating = "good"; + if (ms > -90 * ts && ms < -45 * ts) + rating = "good"; + if (ms < 45 * ts && ms > -45 * ts) + rating = "sick"; + return rating; } public static function CalculateRanking(score:Int,scoreDef:Int,nps:Int,maxNPS:Int,accuracy:Float):String { return (FlxG.save.data.npsDisplay ? // NPS Toggle - "NPS: " + nps + " (Max " + maxNPS + ")" + (!FlxG.save.data.botplay ? " | " : "") : "") + // NPS - (!FlxG.save.data.botplay ? "Score:" + (Conductor.safeFrames != 10 ? score + " (" + scoreDef + ")" : "" + score) + // Score + "NPS: " + nps + " (Max " + maxNPS + ")" + (!PlayStateChangeables.botPlay || PlayState.loadRep ? " | " : "") : "") + // NPS + (!PlayStateChangeables.botPlay || PlayState.loadRep ? "Score:" + (Conductor.safeFrames != 10 ? score + " (" + scoreDef + ")" : "" + score) + // Score (FlxG.save.data.accuracyDisplay ? // Accuracy Toggle " | Combo Breaks:" + PlayState.misses + // Misses/Combo Breaks - " | Accuracy:" + (FlxG.save.data.botplay ? "N/A" : HelperFunctions.truncateFloat(accuracy, 2) + " %") + // Accuracy + " | Accuracy:" + (PlayStateChangeables.botPlay && !PlayState.loadRep ? "N/A" : HelperFunctions.truncateFloat(accuracy, 2) + " %") + // Accuracy " | " + GenerateLetterRank(accuracy) : "") : ""); // Letter Rank } } diff --git a/source/Replay.hx b/source/Replay.hx index c1a89fa..51fddf2 100644 --- a/source/Replay.hx +++ b/source/Replay.hx @@ -17,14 +17,15 @@ typedef ReplayJSON = public var timestamp:Date; public var songName:String; public var songDiff:Int; - public var songNotes:Array; + public var songNotes:Array; public var noteSpeed:Float; public var isDownscroll:Bool; + public var sf:Int; } class Replay { - public static var version:String = "1.1"; // replay file version + public static var version:String = "1.2"; // replay file version public var path:String = ""; public var replay:ReplayJSON; @@ -38,7 +39,8 @@ class Replay isDownscroll: false, songNotes: [], replayGameVer: version, - timestamp: Date.now() + timestamp: Date.now(), + sf: Conductor.safeFrames }; } @@ -48,12 +50,12 @@ class Replay rep.LoadFromJSON(); - trace('basic replay data:\nSong Name: ' + rep.replay.songName + '\nSong Diff: ' + rep.replay.songDiff + '\nNotes Length: ' + rep.replay.songNotes.length); + trace('basic replay data:\nSong Name: ' + rep.replay.songName + '\nSong Diff: ' + rep.replay.songDiff); return rep; } - public function SaveReplay(notearray:Array) + public function SaveReplay(notearray:Array) { var json = { "songName": PlayState.SONG.song, @@ -62,13 +64,20 @@ class Replay "isDownscroll": FlxG.save.data.downscroll, "songNotes": notearray, "timestamp": Date.now(), - "replayGameVer": version + "replayGameVer": version, + "sf": Conductor.safeFrames }; var data:String = Json.stringify(json); + + var time = Date.now().getTime(); #if sys - File.saveContent("assets/replays/replay-" + PlayState.SONG.song + "-time" + Date.now().getTime() + ".kadeReplay", data); + File.saveContent("assets/replays/replay-" + PlayState.SONG.song + "-time" + time + ".kadeReplay", data); + + path = "replay-" + PlayState.SONG.song + "-time" + time + ".kadeReplay"; // for score screen shit + + LoadFromJSON(); #end } diff --git a/source/ResultsScreen.hx b/source/ResultsScreen.hx new file mode 100644 index 0000000..2c8e258 --- /dev/null +++ b/source/ResultsScreen.hx @@ -0,0 +1,250 @@ +package; + +import openfl.geom.Matrix; +import openfl.display.BitmapData; +import flixel.system.FlxSound; +import flixel.util.FlxAxes; +import flixel.FlxSubState; +import Options.Option; +import flixel.input.FlxInput; +import flixel.input.keyboard.FlxKey; +import flixel.FlxG; +import flixel.FlxObject; +import flixel.FlxSprite; +import flixel.effects.FlxFlicker; +import flixel.graphics.frames.FlxAtlasFrames; +import flixel.group.FlxGroup.FlxTypedGroup; +import flixel.text.FlxText; +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import flixel.util.FlxColor; +import io.newgrounds.NG; +import lime.app.Application; +import lime.utils.Assets; +import flixel.math.FlxMath; +import flixel.text.FlxText; +import flixel.input.FlxKeyManager; + + +using StringTools; + +class ResultsScreen extends FlxSubState +{ + public var background:FlxSprite; + public var text:FlxText; + + public var anotherBackground:FlxSprite; + public var graph:HitGraph; + public var graphSprite:FlxSprite; + + public var comboText:FlxText; + public var contText:FlxText; + public var settingsText:FlxText; + + public var music:FlxSound; + + public var graphData:BitmapData; + + public var ranking:String; + public var accuracy:String; + + override function create() + { + background = new FlxSprite(0,0).makeGraphic(FlxG.width,FlxG.height,FlxColor.BLACK); + background.scrollFactor.set(); + add(background); + + music = new FlxSound().loadEmbedded(Paths.music('breakfast'), true, true); + music.volume = 0; + music.play(false, FlxG.random.int(0, Std.int(music.length / 2))); + + background.alpha = 0; + + text = new FlxText(20,-55,0,"Song Cleared!"); + text.size = 34; + text.setBorderStyle(FlxTextBorderStyle.OUTLINE,FlxColor.BLACK,4,1); + text.color = FlxColor.WHITE; + text.scrollFactor.set(); + add(text); + + var score = PlayState.instance.songScore; + if (PlayState.isStoryMode) + { + score = PlayState.campaignScore; + text.text = "Week Cleared!"; + } + + comboText = new FlxText(20,-75,0,'Judgements:\nSicks - ${PlayState.sicks}\nGoods - ${PlayState.goods}\nBads - ${PlayState.bads}\n\nCombo Breaks: ${(PlayState.isStoryMode ? PlayState.campaignMisses : PlayState.misses) + PlayState.shits}\nHighest Combo: ${PlayState.highestCombo + 1}\n\nScore: ${PlayState.instance.songScore}\nAccuracy: ${HelperFunctions.truncateFloat(PlayState.instance.accuracy,2)}%\n\n${Ratings.GenerateLetterRank(PlayState.instance.accuracy)}\n\nF1 - View replay\nF2 - Replay song + '); + comboText.size = 28; + comboText.setBorderStyle(FlxTextBorderStyle.OUTLINE,FlxColor.BLACK,4,1); + comboText.color = FlxColor.WHITE; + comboText.scrollFactor.set(); + add(comboText); + + contText = new FlxText(FlxG.width - 475,FlxG.height + 50,0,'Press ENTER to continue.'); + contText.size = 28; + contText.setBorderStyle(FlxTextBorderStyle.OUTLINE,FlxColor.BLACK,4,1); + contText.color = FlxColor.WHITE; + contText.scrollFactor.set(); + add(contText); + + anotherBackground = new FlxSprite(FlxG.width - 500,45).makeGraphic(450,240,FlxColor.BLACK); + anotherBackground.scrollFactor.set(); + anotherBackground.alpha = 0; + add(anotherBackground); + + graph = new HitGraph(FlxG.width - 500,45,495,240); + graph.alpha = 0; + + graphSprite = new FlxSprite(FlxG.width - 510,45); + + graphSprite.scrollFactor.set(); + graphSprite.alpha = 0; + + add(graphSprite); + + + var sicks = HelperFunctions.truncateFloat(PlayState.sicks / PlayState.goods,1); + var goods = HelperFunctions.truncateFloat(PlayState.goods / PlayState.bads,1); + + if (sicks == Math.POSITIVE_INFINITY) + sicks = 0; + if (goods == Math.POSITIVE_INFINITY) + goods = 0; + + var mean:Float = 0; + + + for (i in PlayState.rep.replay.songNotes) + { + // 0 = time + // 1 = length + // 2 = type + // 3 = diff + var diff = i[3]; + var judge = Ratings.CalculateRating(diff, Math.floor((PlayState.rep.replay.sf / 60) * 1000)); + mean += diff; + if (i[1] != -1) + graph.addToHistory(diff, judge); + } + + graph.update(); + + graphSprite.makeGraphic(460,240,FlxColor.TRANSPARENT); + + graphSprite.pixels.draw(graph); + + mean = HelperFunctions.truncateFloat(mean / PlayState.rep.replay.songNotes.length,2); + + settingsText = new FlxText(20,FlxG.height + 50,0,'SF: ${PlayState.rep.replay.sf} | Ratio (SA/GA): ${Math.round(sicks)}:1 ${Math.round(goods)}:1 | Mean: ${mean}ms | Played on ${PlayState.SONG.song} ${CoolUtil.difficultyString()}'); + settingsText.size = 16; + settingsText.setBorderStyle(FlxTextBorderStyle.OUTLINE,FlxColor.BLACK,2,1); + settingsText.color = FlxColor.WHITE; + settingsText.scrollFactor.set(); + add(settingsText); + + + FlxTween.tween(background, {alpha: 0.5},0.5); + FlxTween.tween(text, {y:20},0.5,{ease: FlxEase.expoInOut}); + FlxTween.tween(comboText, {y:145},0.5,{ease: FlxEase.expoInOut}); + FlxTween.tween(contText, {y:FlxG.height - 45},0.5,{ease: FlxEase.expoInOut}); + FlxTween.tween(settingsText, {y:FlxG.height - 35},0.5,{ease: FlxEase.expoInOut}); + FlxTween.tween(anotherBackground, {alpha: 0.6},0.5, {onUpdate: function(tween:FlxTween) { + graph.alpha = FlxMath.lerp(0,1,tween.percent); + graphSprite.alpha = FlxMath.lerp(0,1,tween.percent); + }}); + + cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]]; + + super.create(); + } + + + var frames = 0; + + override function update(elapsed:Float) + { + if (music.volume < 0.5) + music.volume += 0.01 * elapsed; + + // render + if (frames != 2) + { + graphSprite.pixels.draw(graph); + frames++; + } + // keybinds + + if (FlxG.keys.justPressed.ENTER) + { + music.fadeOut(0.3); + + PlayState.loadRep = false; + PlayState.rep = null; + + if (PlayState.isStoryMode) + { + FlxG.sound.playMusic(Paths.music('freakyMenu')); + FlxG.switchState(new MainMenuState()); + } + else + FlxG.switchState(new FreeplayState()); + } + + if (FlxG.keys.justPressed.F1) + { + trace(PlayState.rep.path); + PlayState.rep = Replay.LoadReplay(PlayState.rep.path); + + PlayState.loadRep = true; + + var songFormat = StringTools.replace(PlayState.rep.replay.songName, " ", "-"); + switch (songFormat) { + case 'Dad-Battle': songFormat = 'Dadbattle'; + case 'Philly-Nice': songFormat = 'Philly'; + // Replay v1.0 support + case 'dad-battle': songFormat = 'Dadbattle'; + case 'philly-nice': songFormat = 'Philly'; + } + + var poop:String = Highscore.formatSong(songFormat, PlayState.rep.replay.songDiff); + + music.fadeOut(0.3); + + PlayState.SONG = Song.loadFromJson(poop, PlayState.rep.replay.songName); + PlayState.isStoryMode = false; + PlayState.storyDifficulty = PlayState.rep.replay.songDiff; + PlayState.storyWeek = 0; + LoadingState.loadAndSwitchState(new PlayState()); + } + + if (FlxG.keys.justPressed.F2 ) + { + PlayState.rep = null; + + PlayState.loadRep = false; + + var songFormat = StringTools.replace(PlayState.SONG.song, " ", "-"); + switch (songFormat) { + case 'Dad-Battle': songFormat = 'Dadbattle'; + case 'Philly-Nice': songFormat = 'Philly'; + case 'dad-battle': songFormat = 'Dadbattle'; + case 'philly-nice': songFormat = 'Philly'; + } + + var poop:String = Highscore.formatSong(songFormat, PlayState.storyDifficulty); + + music.fadeOut(0.3); + + PlayState.SONG = Song.loadFromJson(poop, PlayState.SONG.song); + PlayState.isStoryMode = false; + PlayState.storyDifficulty = PlayState.storyDifficulty; + PlayState.storyWeek = 0; + LoadingState.loadAndSwitchState(new PlayState()); + } + + super.update(elapsed); + + } +} diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx index 98c2680..0b59740 100644 --- a/source/StoryMenuState.hx +++ b/source/StoryMenuState.hx @@ -313,7 +313,11 @@ class StoryMenuState extends MusicBeatState } var poop:String = Highscore.formatSong(songFormat, curDifficulty); - + PlayState.sicks = 0; + PlayState.bads = 0; + PlayState.shits = 0; + PlayState.goods = 0; + PlayState.campaignMisses = 0; PlayState.SONG = Song.loadFromJson(poop, PlayState.storyPlaylist[0]); PlayState.storyWeek = curWeek; PlayState.campaignScore = 0; diff --git a/version.downloadMe b/version.downloadMe index b8cb634..b03f579 100644 --- a/version.downloadMe +++ b/version.downloadMe @@ -1,11 +1,6 @@ -1.5.2; -- (1.5.2) Fix crashes on some songs -- Added toggle for ghost tapping -- Officially support macOS (and add macOS requirements to docs) -- Autoplay -- Clap assist for syncing charts -- Bring back R to reset, but now you can toggle it in the options -- You can now fully customize your keybinds -- Change how replays work + store scroll speed and direction in replays -- Opponent strumline now lights up when they hit a note, like the player's does -- Now using the new recharts from Funkin v0.2.8 +1.5.3; +- Score Screen +- Rewrote the entire hit ranking system +- Fixed song names so they don't crash +- New asset loading system +- New Logo \ No newline at end of file