diff --git a/checkstyle.json b/checkstyle.json index 445f82b42..d41a6d617 100644 --- a/checkstyle.json +++ b/checkstyle.json @@ -23,10 +23,10 @@ }, { "props": { - "allowSingleArgParens": false, - "allowReturn": false, - "allowFunction": false, - "allowCurlyBody": false + "allowSingleArgParens": true, + "allowReturn": true, + "allowFunction": true, + "allowCurlyBody": true }, "type": "ArrowFunction" }, @@ -80,7 +80,7 @@ "props": { "ignoreExtern": true, "format": "^[A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$", - "tokens": [] + "tokens": ["INLINE", "NOTINLINE"] }, "type": "ConstantName" }, @@ -178,13 +178,7 @@ "fieldType": "BOTH", "requireReturn": true, "ignoreOverride": true, - "tokens": [ - "ABSTRACT_DEF", - "CLASS_DEF", - "ENUM_DEF", - "INTERFACE_DEF", - "TYPEDEF_DEF" - ], + "tokens": ["ABSTRACT_DEF", "CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF"], "modifier": "PUBLIC", "excludeNames": ["new", "toString"] }, @@ -198,10 +192,6 @@ }, "type": "FileLength" }, - { - "props": {}, - "type": "Final" - }, { "props": { "option": "upperCase" @@ -375,7 +365,7 @@ }, { "props": { - "max": 1 + "max": 4 }, "type": "NestedIfDepth" }, @@ -387,7 +377,7 @@ }, { "props": { - "option": "nullDefault" + "option": "questionMark" }, "type": "NullableParameter" }, @@ -396,7 +386,6 @@ "oldFunctionTypePolicy": "none", "unaryOpPolicy": "none", "intervalOpPolicy": "none", - "newFunctionTypePolicy": "around", "ternaryOpPolicy": "around", "boolOpPolicy": "around", @@ -589,19 +578,7 @@ }, { "props": { - "ignoreEnumAbstractValues": true - }, - "type": "Type" - }, - { - "props": { - "tokens": [ - "ABSTRACT_DEF", - "CLASS_DEF", - "ENUM_DEF", - "INTERFACE_DEF", - "TYPEDEF_DEF" - ] + "tokens": ["CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF", "TYPEDEF_DEF"] }, "type": "TypeDocComment" }, @@ -630,12 +607,6 @@ }, "type": "UnusedLocalVar" }, - { - "props": { - "severity": "IGNORE" - }, - "type": "VariableInitialisation" - }, { "props": { "typeHintPolicy": "enforce_all", diff --git a/hxformat.json b/hxformat.json index cacbbf810..88a528e34 100644 --- a/hxformat.json +++ b/hxformat.json @@ -1,31 +1,30 @@ -{ - "disableFormatting": false, - - "indentation": { - "character": " ", - "tabWidth": 2, - "indentCaseLabels": true - }, - - "lineEnds": { - "anonFunctionCurly": { - "emptyCurly": "break", - "leftCurly": "after", - "rightCurly": "both" - }, - "leftCurly": "both", - "rightCurly": "both" - }, - - "sameLine": { - "ifBody": "same", - "ifElse": "next", - "doWhile": "next", - "tryBody": "next", - "tryCatch": "next" - }, - - "whitespace": { - "switchPolicy": "around" - } -} +{ + "disableFormatting": false, + + "indentation": { + "character": " ", + "tabWidth": 2, + "indentCaseLabels": true + }, + "lineEnds": { + "anonFunctionCurly": { + "emptyCurly": "break", + "leftCurly": "after", + "rightCurly": "both" + }, + "leftCurly": "both", + "rightCurly": "both" + }, + + "sameLine": { + "ifBody": "same", + "ifElse": "next", + "doWhile": "next", + "tryBody": "next", + "tryCatch": "next" + }, + + "whitespace": { + "switchPolicy": "around" + } +} diff --git a/source/funkin/Highscore.hx b/source/funkin/Highscore.hx index 24b65832b..996e2367e 100644 --- a/source/funkin/Highscore.hx +++ b/source/funkin/Highscore.hx @@ -5,7 +5,42 @@ package funkin; */ class Highscore { + /** + * Keeps track of notes hit for the current song + * and how accurate you were with each note (bad, missed, shit, etc.) + */ public static var tallies:Tallies = new Tallies(); + + /** + * Keeps track of notes hit for the current WEEK / level + * for use with storymode, or likely any other "playlist" esque option + */ + public static var talliesLevel:Tallies = new Tallies(); + + /** + * Produces a new Tallies object which represents the sum of two existing Tallies + * @param newTally The first tally + * @param baseTally The second tally + * @return The combined tally + */ + public static function combineTallies(newTally:Tallies, baseTally:Tallies):Tallies + { + var combinedTally:Tallies = new Tallies(); + combinedTally.missed = newTally.missed + baseTally.missed; + combinedTally.shit = newTally.shit + baseTally.shit; + combinedTally.bad = newTally.bad + baseTally.bad; + combinedTally.good = newTally.good + baseTally.good; + combinedTally.sick = newTally.sick + baseTally.sick; + combinedTally.totalNotes = newTally.totalNotes + baseTally.totalNotes; + combinedTally.totalNotesHit = newTally.totalNotesHit + baseTally.totalNotesHit; + + // Current combo = use most recent. + combinedTally.combo = newTally.combo; + // Max combo = use maximum value. + combinedTally.maxCombo = Std.int(Math.max(newTally.maxCombo, baseTally.maxCombo)); + + return combinedTally; + } } @:forward @@ -29,6 +64,9 @@ abstract Tallies(RawTallies) } } +/** + * A structure object containing the data for highscore tallies. + */ typedef RawTallies = { var combo:Int; @@ -51,7 +89,7 @@ typedef RawTallies = var totalNotesHit:Int; /** - * How many notes PASSED BY AND/OR HIT!!! + * How many notes in the current chart */ var totalNotes:Int; } diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 2368d09f2..9ecf66ec7 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -32,6 +32,7 @@ import funkin.util.CLIUtil; import funkin.util.CLIUtil.CLIParams; import funkin.util.tools.TimerTools; import funkin.ui.transition.LoadingState; +import funkin.util.TrackerUtil; #if discord_rpc import Discord.DiscordClient; #end @@ -67,7 +68,7 @@ class InitState extends FlxState /** * Setup a bunch of important Flixel stuff. */ - function setupShit() + function setupShit():Void { // // GAME SETUP @@ -95,7 +96,7 @@ class InitState extends FlxState #if (debug || FORCE_DEBUG_VERSION) // Disable using ~ to open the console (we use that for the Editor menu) FlxG.debugger.toggleKeys = [F2]; - + TrackerUtil.initTrackers(); // Adds an additional Close Debugger button. // This big obnoxious white button is for MOBILE, so that you can press it // easily with your finger when debug bullshit pops up during testing lol! diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 06ba48e81..a1e14d705 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -90,6 +90,11 @@ class FunkinSound extends FlxSound implements ICloneable */ var _label:String = "unknown"; + /** + * Whether we received a focus lost event. + */ + var _lostFocus:Bool = false; + public function new() { super(); @@ -167,8 +172,18 @@ class FunkinSound extends FlxSound implements ICloneable public override function pause():FunkinSound { - super.pause(); - this._shouldPlay = false; + if (_shouldPlay) + { + // This sound will eventually play, but is still at a negative timestamp. + // Manually set the paused flag to ensure proper focus/unfocus behavior. + _shouldPlay = false; + _paused = true; + active = false; + } + else + { + super.pause(); + } return this; } @@ -177,7 +192,10 @@ class FunkinSound extends FlxSound implements ICloneable */ override function onFocus():Void { - if (!_alreadyPaused) + // Flixel can sometimes toss spurious `onFocus` events, e.g. if the Flixel debugger is toggled + // on and off. We only want to resume the sound if we actually lost focus, and if we weren't + // already paused before we lost focus. + if (_lostFocus && !_alreadyPaused) { resume(); } @@ -185,6 +203,7 @@ class FunkinSound extends FlxSound implements ICloneable { trace('Not resuming audio on focus!'); } + _lostFocus = false; } /** @@ -193,6 +212,7 @@ class FunkinSound extends FlxSound implements ICloneable override function onFocusLost():Void { trace('Focus lost, pausing audio!'); + _lostFocus = true; _alreadyPaused = _paused; pause(); } @@ -201,7 +221,10 @@ class FunkinSound extends FlxSound implements ICloneable { if (this._time < 0) { - this._shouldPlay = true; + // Sound with negative timestamp, restart the timer. + _shouldPlay = true; + _paused = false; + active = true; } else { diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index 24febea86..938859ff2 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -106,6 +106,8 @@ class SongMetadata implements ICloneable /** * Serialize this SongMetadata into a JSON string. + * @param pretty Whether the JSON should be big ol string (false), + * or formatted with tabs (true) * @return The JSON string. */ public function serialize(pretty:Bool = true):String diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index d090b4f8a..b41c29c83 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1732,7 +1732,6 @@ class PlayState extends MusicBeatSubState if (strumTime < startTime) continue; // Skip notes that are before the start time. var noteData:Int = songNote.getDirection(); - var playerNote:Bool = true; if (noteData > 3) playerNote = false; @@ -1741,6 +1740,8 @@ class PlayState extends MusicBeatSubState { case 0: playerNoteData.push(songNote); + // increment totalNotes for total possible notes able to be hit by the player + Highscore.tallies.totalNotes++; case 1: opponentNoteData.push(songNote); } @@ -2622,6 +2623,9 @@ class PlayState extends MusicBeatSubState accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, }; + // adds current song data into the tallies for the level (story levels) + Highscore.talliesLevel = Highscore.combineTallies(Highscore.tallies, Highscore.talliesLevel); + if (Save.instance.isSongHighScore(currentSong.id, currentDifficulty, data)) { Save.instance.setSongScore(currentSong.id, currentDifficulty, data); @@ -2890,11 +2894,14 @@ class PlayState extends MusicBeatSubState persistentUpdate = false; vocals.stop(); camHUD.alpha = 1; + + var talliesToUse:Tallies = PlayStatePlaylist.isStoryMode ? Highscore.talliesLevel : Highscore.tallies; + var res:ResultState = new ResultState( { storyMode: PlayStatePlaylist.isStoryMode, title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), - tallies: Highscore.tallies, + tallies: talliesToUse, }); res.camera = camHUD; openSubState(res); diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 223043c28..f77c3fc6b 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -2,27 +2,25 @@ package funkin.play; import funkin.ui.story.StoryMenuState; import funkin.graphics.adobeanimate.FlxAtlasSprite; -import flixel.FlxBasic; import flixel.FlxSprite; import funkin.graphics.FunkinSprite; -import flixel.graphics.frames.FlxAtlasFrames; import flixel.graphics.frames.FlxBitmapFont; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.math.FlxPoint; import funkin.ui.MusicBeatSubState; import flixel.math.FlxRect; import flixel.text.FlxBitmapText; -import flixel.text.FlxText; import flixel.tweens.FlxEase; import funkin.ui.freeplay.FreeplayState; import flixel.tweens.FlxTween; -import flixel.util.FlxColor; import flixel.util.FlxGradient; import flixel.util.FlxTimer; import funkin.graphics.shaders.LeftMaskShader; import funkin.play.components.TallyCounter; -import flxanimate.FlxAnimate.Settings; +/** + * The state for the results screen after a song or week is finished. + */ class ResultState extends MusicBeatSubState { final params:ResultsStateParams; @@ -31,8 +29,8 @@ class ResultState extends MusicBeatSubState var songName:FlxBitmapText; var difficulty:FlxSprite; - var maskShaderSongName = new LeftMaskShader(); - var maskShaderDifficulty = new LeftMaskShader(); + var maskShaderSongName:LeftMaskShader = new LeftMaskShader(); + var maskShaderDifficulty:LeftMaskShader = new LeftMaskShader(); public function new(params:ResultsStateParams) { @@ -50,22 +48,22 @@ class ResultState extends MusicBeatSubState else resultsVariation = NORMAL; - var loops = resultsVariation != SHIT; + var loops:Bool = resultsVariation != SHIT; FlxG.sound.playMusic(Paths.music("results" + resultsVariation), 1, loops); // TEMP-ish, just used to sorta "cache" the 3000x3000 image! - var cacheBullShit = new FlxSprite().loadGraphic(Paths.image("resultScreen/soundSystem")); + var cacheBullShit:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/soundSystem")); add(cacheBullShit); - var dumb = new FlxSprite().loadGraphic(Paths.image("resultScreen/scorePopin")); + var dumb:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/scorePopin")); add(dumb); var bg:FlxSprite = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFECC5C, 0xFFFDC05C], 90); bg.scrollFactor.set(); add(bg); - var bgFlash:FlxSprite = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFffeb69, 0xFFffe66a], 90); + var bgFlash:FlxSprite = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFEB69, 0xFFFFE66A], 90); bgFlash.scrollFactor.set(); bgFlash.visible = false; add(bgFlash); @@ -188,6 +186,10 @@ class ResultState extends MusicBeatSubState var ratingGrp:FlxTypedGroup = new FlxTypedGroup(); add(ratingGrp); + /** + * NOTE: We display how many notes were HIT, not how many notes there were in total. + * + */ var totalHit:TallyCounter = new TallyCounter(375, hStuf * 3, params.tallies.totalNotesHit); ratingGrp.add(totalHit); @@ -202,7 +204,7 @@ class ResultState extends MusicBeatSubState var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, params.tallies.good, 0xFF89C9E5); ratingGrp.add(tallyGood); - var tallyBad:TallyCounter = new TallyCounter(190, (hStuf * 7) + extraYOffset, params.tallies.bad, 0xffE6CF8A); + var tallyBad:TallyCounter = new TallyCounter(190, (hStuf * 7) + extraYOffset, params.tallies.bad, 0xFFE6CF8A); ratingGrp.add(tallyBad); var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, params.tallies.shit, 0xFFE68C8A); @@ -274,13 +276,13 @@ class ResultState extends MusicBeatSubState super.create(); } - function timerThenSongName() + function timerThenSongName():Void { movingSongStuff = false; difficulty.x = 555; - var diffYTween = 122; + var diffYTween:Float = 122; difficulty.y = -difficulty.height; FlxTween.tween(difficulty, {y: diffYTween}, 0.5, {ease: FlxEase.quartOut, startDelay: 0.8}); @@ -310,7 +312,7 @@ class ResultState extends MusicBeatSubState // maskShaderSongName.frameUV = songName.frame.uv; } - override function update(elapsed:Float) + override function update(elapsed:Float):Void { // maskShaderSongName.swagSprX = songName.x; maskShaderDifficulty.swagSprX = difficulty.x; diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index 8b477feee..404dfb67e 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -520,7 +520,7 @@ class StoryMenuState extends MusicBeatState } } - function selectLevel() + function selectLevel():Void { if (!currentLevel.isUnlocked()) { @@ -555,6 +555,8 @@ class StoryMenuState extends MusicBeatState PlayStatePlaylist.campaignTitle = currentLevel.getTitle(); PlayStatePlaylist.campaignDifficulty = currentDifficultyId; + Highscore.talliesLevel = new funkin.Highscore.Tallies(); + new FlxTimer().start(1, function(tmr:FlxTimer) { FlxTransitionableState.skipNextTransIn = false; FlxTransitionableState.skipNextTransOut = false; diff --git a/source/funkin/util/TrackerUtil.hx b/source/funkin/util/TrackerUtil.hx new file mode 100644 index 000000000..b8ed0c995 --- /dev/null +++ b/source/funkin/util/TrackerUtil.hx @@ -0,0 +1,23 @@ +package funkin.util; + +// This may or may not already be imported via imports.hx... +import flixel.system.debug.watch.Tracker; +import flixel.FlxG; + +/** + * Utility class that helps manage adding profiles to the flixel debugger tracker + */ +class TrackerUtil +{ + /** + * Adds profiles to the debugger to help track certain game objects. + * NOTE: This isn't the full list of profiles made, as sometimes they're made + * on in various places in code for random debugging purposes! + * Might be good to put them all here though! + */ + public static function initTrackers():Void + { + Tracker.addProfile(new TrackerProfile(Highscore, ["tallies"])); + FlxG.console.registerClass(Highscore); + } +}