diff --git a/source/ChartingState.hx b/source/ChartingState.hx index 8e959f9..4371fad 100644 --- a/source/ChartingState.hx +++ b/source/ChartingState.hx @@ -1239,7 +1239,7 @@ class ChartingState extends MusicBeatState var daStrumTime = i[0]; var daSus = i[2]; - var note:Note = new Note(daStrumTime, daNoteInfo % 4); + var note:Note = new Note(daStrumTime, daNoteInfo % 4,null,false,true); note.sustainLength = daSus; note.setGraphicSize(GRID_SIZE, GRID_SIZE); note.updateHitbox(); diff --git a/source/HitGraph.hx b/source/HitGraph.hx index e3b3790..7b1d383 100644 --- a/source/HitGraph.hx +++ b/source/HitGraph.hx @@ -1,3 +1,4 @@ +import flixel.FlxG; import openfl.display.Bitmap; import openfl.display.BitmapData; import openfl.text.TextFieldAutoSize; @@ -29,6 +30,8 @@ class HitGraph extends Sprite 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 showInput:Bool = FlxG.save.data.inputShow; + public var graphColor:FlxColor; public var history:Array = []; @@ -185,14 +188,33 @@ class HitGraph extends Sprite 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; + if (showInput) + { + for (i in 0...PlayState.rep.replay.ana.anaArray.length) + { + var ana = PlayState.rep.replay.ana.anaArray[i]; + + var value = (ana.key * 25 - minValue) / range; + + if (ana.hit) + gfx.beginFill(0xFFFF00); + else + gfx.beginFill(0xC2B280); + + if (ana.hitTime < 0) + continue; + + var pointY = (-value * _height - 1) + _height; + gfx.drawRect(graphX + fitX(ana.hitTime), pointY,2,2); + gfx.endFill(); + } + } + for (i in 0...history.length) { - var value = (history[i][0] - minValue) / range; var judge = history[i][1]; @@ -212,21 +234,28 @@ class HitGraph extends Sprite 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.drawRect(graphX + fitX(history[i][2]), 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) + public function fitX(x:Float) { - history.push([diff,judge]); + return (x / FlxG.sound.music.length) * width; + } + + public function addToHistory(diff:Float, judge:String, time:Float) + { + history.push([diff,judge, time]); } public function update():Void diff --git a/source/KadeEngineData.hx b/source/KadeEngineData.hx index 37841d2..1ad2516 100644 --- a/source/KadeEngineData.hx +++ b/source/KadeEngineData.hx @@ -90,6 +90,9 @@ class KadeEngineData if (FlxG.save.data.scoreScreen == null) FlxG.save.data.scoreScreen = true; + if (FlxG.save.data.inputShow == null) + FlxG.save.data.inputShow = false; + Conductor.recalculateTimings(); PlayerSettings.player1.controls.loadKeyBinds(); KeyBinds.keyCheck(); diff --git a/source/Note.hx b/source/Note.hx index f7f915e..cdb9cb2 100644 --- a/source/Note.hx +++ b/source/Note.hx @@ -37,7 +37,7 @@ class Note extends FlxSprite public var rating:String = "shit"; - public function new(strumTime:Float, noteData:Int, ?prevNote:Note, ?sustainNote:Bool = false) + public function new(strumTime:Float, noteData:Int, ?prevNote:Note, ?sustainNote:Bool = false, ?inCharter:Bool = false) { super(); @@ -50,7 +50,10 @@ class Note extends FlxSprite x += 50; // MAKE SURE ITS DEFINITELY OFF SCREEN? y -= 2000; - this.strumTime = Math.round(strumTime); + if (inCharter) + this.strumTime = strumTime; + else + this.strumTime = Math.round(strumTime); if (this.strumTime < 0 ) this.strumTime = 0; diff --git a/source/OFLSprite.hx b/source/OFLSprite.hx new file mode 100644 index 0000000..abea3a0 --- /dev/null +++ b/source/OFLSprite.hx @@ -0,0 +1,39 @@ +import flixel.util.FlxColor; +import openfl.display.Sprite; +import flixel.FlxSprite; + +/** + * designed to draw a Open FL Sprite as a FlxSprite (to allow layering and auto sizing for haxe flixel cameras) + * Custom made for Kade Engine + */ +class OFLSprite extends FlxSprite +{ + public var flSprite:Sprite; + + public function new(x,y,width,height,Sprite:Sprite) + { + super(x,y); + + makeGraphic(width,height,FlxColor.TRANSPARENT); + + flSprite = Sprite; + + pixels.draw(flSprite); + } + + private var _frameCount:Int = 0; + + override function update(elapsed:Float) + { + if (_frameCount != 2) + { + pixels.draw(flSprite); + _frameCount++; + } + } + + public function updateDisplay() + { + pixels.draw(flSprite); + } +} \ No newline at end of file diff --git a/source/Options.hx b/source/Options.hx index d5e82c2..58f770f 100644 --- a/source/Options.hx +++ b/source/Options.hx @@ -261,6 +261,27 @@ class FlashingLightsOption extends Option } } +class ShowInput extends Option +{ + public function new(desc:String) + { + super(); + description = desc; + } + public override function press():Bool + { + FlxG.save.data.inputShow = !FlxG.save.data.inputShow; + display = updateDisplay(); + return true; + } + + private override function updateDisplay():String + { + return (FlxG.save.data.inputShow ? "Extended Score Info" : "Minimalized Info"); + } +} + + class Judgement extends Option { diff --git a/source/OptionsMenu.hx b/source/OptionsMenu.hx index f5d8830..841d9ea 100644 --- a/source/OptionsMenu.hx +++ b/source/OptionsMenu.hx @@ -57,8 +57,9 @@ class OptionsMenu extends MusicBeatState #end 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 BotPlay("Showcase your charts and mods with autoplay."), + new ScoreScreen("Show the score screen after the end of a song"), + new ShowInput("Display every single input in the score screen.") ]), new OptionCategory("Manage Save Data", [ diff --git a/source/PlayState.hx b/source/PlayState.hx index 32cffe9..abc4b03 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -1,5 +1,7 @@ package; +import Replay.Ana; +import Replay.Analysis; import webm.WebmPlayer; import flixel.input.keyboard.FlxKey; import haxe.Exception; @@ -212,6 +214,8 @@ class PlayState extends MusicBeatState private var botPlayState:FlxText; // Replay shit private var saveNotes:Array = []; + private var saveJudge:Array = []; + private var replayAna:Analysis = new Analysis(); // replay analysis public static var highestCombo:Int = 0; @@ -1966,7 +1970,7 @@ class PlayState extends MusicBeatState FlxG.switchState(new Charting()); */ #if debug - if (FlxG.keys.justPressed.EIGHT) + if (FlxG.keys.justPressed.SIX) { if (useVideo) { @@ -2555,7 +2559,7 @@ class PlayState extends MusicBeatState campaignMisses = misses; if (!loadRep) - rep.SaveReplay(saveNotes); + rep.SaveReplay(saveNotes, saveJudge, replayAna); else { PlayStateChangeables.botPlay = false; @@ -2693,7 +2697,7 @@ class PlayState extends MusicBeatState if (FlxG.save.data.scoreScreen) openSubState(new ResultsScreen()); else - FlxG.switchState(new PlayState()); + FlxG.switchState(new FreeplayState()); } } } @@ -3026,6 +3030,7 @@ class PlayState extends MusicBeatState }; #end + // Prevent player input if botplay is on if(PlayStateChangeables.botPlay) { @@ -3033,6 +3038,13 @@ class PlayState extends MusicBeatState pressArray = [false, false, false, false]; releaseArray = [false, false, false, false]; } + + var anas:Array = [null,null,null,null]; + + for (i in 0...pressArray.length) + if (pressArray[i]) + anas[i] = new Ana(Conductor.songPosition, null, false, "miss", i); + // HOLDS, check for sustain notes if (holdArray.contains(true) && /*!boyfriend.stunned && */ generatedMusic) { @@ -3059,30 +3071,9 @@ class PlayState extends MusicBeatState { if (!directionsAccounted[daNote.noteData]) { - if (directionList.contains(daNote.noteData)) - { - directionsAccounted[daNote.noteData] = true; - for (coolNote in possibleNotes) - { - if (coolNote.noteData == daNote.noteData && Math.abs(daNote.strumTime - coolNote.strumTime) < 10) - { // if it's the same note twice at < 10ms distance, just delete it - // EXCEPT u cant delete it in this loop cuz it fucks with the collection lol - dumbNotes.push(daNote); - break; - } - else if (coolNote.noteData == daNote.noteData && daNote.strumTime < coolNote.strumTime) - { // if daNote is earlier than existing note (coolNote), replace - possibleNotes.remove(coolNote); - possibleNotes.push(daNote); - break; - } - } - } - else - { - possibleNotes.push(daNote); - directionList.push(daNote.noteData); - } + directionsAccounted[daNote.noteData] = true; + possibleNotes.push(daNote); + directionList.push(daNote.noteData); } } }); @@ -3096,18 +3087,10 @@ class PlayState extends MusicBeatState } possibleNotes.sort((a, b) -> Std.int(a.strumTime - b.strumTime)); - - var dontCheck = false; - - for (i in 0...pressArray.length) - { - if (pressArray[i] && !directionList.contains(i)) - dontCheck = true; - } if (perfectMode) goodNoteHit(possibleNotes[0]); - else if (possibleNotes.length > 0 && !dontCheck) + else if (possibleNotes.length > 0) { if (!FlxG.save.data.ghost) { @@ -3124,6 +3107,10 @@ class PlayState extends MusicBeatState if (mashViolations != 0) mashViolations--; scoreTxt.color = FlxColor.WHITE; + var noteDiff:Float = -(coolNote.strumTime - Conductor.songPosition); + anas[coolNote.noteData].hit = true; + anas[coolNote.noteData].hitJudge = Ratings.CalculateRating(noteDiff, Math.floor((PlayStateChangeables.safeFrames / 60) * 1000)); + anas[coolNote.noteData].nearestNote = [coolNote.strumTime,coolNote.noteData,coolNote.sustainLength]; goodNoteHit(coolNote); } } @@ -3135,19 +3122,12 @@ class PlayState extends MusicBeatState noteMiss(shit, null); } - if(dontCheck && possibleNotes.length > 0 && FlxG.save.data.ghost && !PlayStateChangeables.botPlay) - { - if (mashViolations > 8) - { - trace('mash violations ' + mashViolations); - scoreTxt.color = FlxColor.RED; - noteMiss(0,null); - } - else - mashViolations++; - } - } + + if (!loadRep) + for (i in anas) + if (i != null) + replayAna.anaArray.push(i); // put em all there notes.forEachAlive(function(daNote:Note) { @@ -3211,6 +3191,17 @@ class PlayState extends MusicBeatState return null; } + public function findByTimeIndex(time:Float):Int + { + for (i in 0...rep.replay.songNotes.length) + { + //trace('checking ' + Math.round(i[0]) + ' against ' + Math.round(time)); + if (rep.replay.songNotes[i][0] == time) + return i; + } + return -1; + } + public var fuckingVolume:Float = 1; public var useVideo = false; @@ -3310,11 +3301,17 @@ class PlayState extends MusicBeatState if (daNote != null) { if (!loadRep) + { saveNotes.push([daNote.strumTime,0,direction,166 * Math.floor((PlayState.rep.replay.sf / 60) * 1000) / 166]); + saveJudge.push("miss"); + } } else if (!loadRep) + { saveNotes.push([Conductor.songPosition,0,direction,166 * Math.floor((PlayState.rep.replay.sf / 60) * 1000) / 166]); + saveJudge.push("miss"); + } //var noteDiff:Float = Math.abs(daNote.strumTime - Conductor.songPosition); //var wife:Float = EtternaFunctions.wife3(noteDiff, FlxG.save.data.etternaMode ? 1 : 1.7); @@ -3456,9 +3453,12 @@ class PlayState extends MusicBeatState var noteDiff:Float = -(note.strumTime - Conductor.songPosition); if(loadRep) + { noteDiff = findByTime(note.strumTime)[3]; - - note.rating = Ratings.CalculateRating(noteDiff); + note.rating = rep.replay.songJudgements[findByTimeIndex(note.strumTime)]; + } + else + note.rating = Ratings.CalculateRating(noteDiff); if (note.rating == "miss") return; @@ -3510,6 +3510,7 @@ class PlayState extends MusicBeatState array[1] = -1; trace('pushing ' + array[0]); saveNotes.push(array); + saveJudge.push(note.rating); } playerStrums.forEach(function(spr:FlxSprite) diff --git a/source/Ratings.hx b/source/Ratings.hx index 92b0ee5..758f8bf 100644 --- a/source/Ratings.hx +++ b/source/Ratings.hx @@ -119,21 +119,21 @@ class Ratings public static function checkRating(ms:Float, ts:Float) { - var rating = "miss"; - if (ms < 166 * ts && ms > 135 * ts) + var rating = "sick"; + 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) + 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) + 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) + if (ms < 45 * ts && ms >= -45 * ts) rating = "sick"; + if (ms > -90 * ts && ms <= -45 * ts) + rating = "good"; + if (ms > -135 * ts && ms <= -90 * ts) + rating = "bad"; + if (ms > -166 * ts && ms <= -135 * ts) + rating = "shit"; return rating; } diff --git a/source/Replay.hx b/source/Replay.hx index 51fddf2..18ce656 100644 --- a/source/Replay.hx +++ b/source/Replay.hx @@ -11,6 +11,31 @@ import haxe.Json; import flixel.input.keyboard.FlxKey; import openfl.utils.Dictionary; +class Ana +{ + public var hitTime:Float; + public var nearestNote:Array; + public var hit:Bool; + public var hitJudge:String; + public var key:Int; + public function new(_hitTime:Float,_nearestNote:Array,_hit:Bool,_hitJudge:String, _key:Int) { + hitTime = _hitTime; + nearestNote = _nearestNote; + hit = _hit; + hitJudge = _hitJudge; + key = _key; + } +} + +class Analysis +{ + public var anaArray:Array; + + public function new() { + anaArray = []; + } +} + typedef ReplayJSON = { public var replayGameVer:String; @@ -18,9 +43,11 @@ typedef ReplayJSON = public var songName:String; public var songDiff:Int; public var songNotes:Array; + public var songJudgements:Array; public var noteSpeed:Float; public var isDownscroll:Bool; public var sf:Int; + public var ana:Analysis; } class Replay @@ -40,7 +67,9 @@ class Replay songNotes: [], replayGameVer: version, timestamp: Date.now(), - sf: Conductor.safeFrames + sf: Conductor.safeFrames, + ana: new Analysis(), + songJudgements: [] }; } @@ -55,7 +84,7 @@ class Replay return rep; } - public function SaveReplay(notearray:Array) + public function SaveReplay(notearray:Array, judge:Array, ana:Analysis) { var json = { "songName": PlayState.SONG.song, @@ -63,9 +92,11 @@ class Replay "noteSpeed": (FlxG.save.data.scrollSpeed > 1 ? FlxG.save.data.scrollSpeed : PlayState.SONG.speed), "isDownscroll": FlxG.save.data.downscroll, "songNotes": notearray, + "songJudgements": judge, "timestamp": Date.now(), "replayGameVer": version, - "sf": Conductor.safeFrames + "sf": Conductor.safeFrames, + "ana": ana }; var data:String = Json.stringify(json); @@ -78,6 +109,8 @@ class Replay path = "replay-" + PlayState.SONG.song + "-time" + time + ".kadeReplay"; // for score screen shit LoadFromJSON(); + + replay.ana = ana; #end } diff --git a/source/ResultsScreen.hx b/source/ResultsScreen.hx index 2c8e258..8541ccc 100644 --- a/source/ResultsScreen.hx +++ b/source/ResultsScreen.hx @@ -35,7 +35,7 @@ class ResultsScreen extends FlxSubState public var anotherBackground:FlxSprite; public var graph:HitGraph; - public var graphSprite:FlxSprite; + public var graphSprite:OFLSprite; public var comboText:FlxText; public var contText:FlxText; @@ -97,7 +97,7 @@ class ResultsScreen extends FlxSubState graph = new HitGraph(FlxG.width - 500,45,495,240); graph.alpha = 0; - graphSprite = new FlxSprite(FlxG.width - 510,45); + graphSprite = new OFLSprite(FlxG.width - 510,45,460,240,graph); graphSprite.scrollFactor.set(); graphSprite.alpha = 0; @@ -116,28 +116,30 @@ class ResultsScreen extends FlxSubState var mean:Float = 0; - for (i in PlayState.rep.replay.songNotes) + for (i in 0...PlayState.rep.replay.songNotes.length) { // 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)); + var obj = PlayState.rep.replay.songNotes[i]; + // judgement + var obj2 = PlayState.rep.replay.songJudgements[i]; + + var obj3 = obj[0]; + + var diff = obj[3]; + var judge = obj2; mean += diff; - if (i[1] != -1) - graph.addToHistory(diff, judge); + if (obj[1] != -1) + graph.addToHistory(diff, judge, obj3); } 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 = 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.difficultyFromInt(PlayState.storyDifficulty).toUpperCase()}'); settingsText.size = 16; settingsText.setBorderStyle(FlxTextBorderStyle.OUTLINE,FlxColor.BLACK,2,1); settingsText.color = FlxColor.WHITE; @@ -168,12 +170,6 @@ class ResultsScreen extends FlxSubState 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) @@ -192,6 +188,12 @@ class ResultsScreen extends FlxSubState FlxG.switchState(new FreeplayState()); } + if (FlxG.keys.justPressed.EIGHT) + { + graph.showInput = !graph.showInput; + graph.update(); + } + if (FlxG.keys.justPressed.F1) { trace(PlayState.rep.path);