From 1e888658f75eb859f51b698ddde8a5d3af188e8b Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 26 Mar 2024 12:33:54 -0400 Subject: [PATCH 01/24] First implementation of credits state. --- Project.xml | 1 + assets | 2 +- source/funkin/data/BaseRegistry.hx | 9 - source/funkin/data/JsonFile.hx | 10 + source/funkin/data/song/SongRegistry.hx | 6 +- source/funkin/ui/credits/CreditsData.hx | 26 +++ .../funkin/ui/credits/CreditsDataHandler.hx | 130 ++++++++++++ source/funkin/ui/credits/CreditsDataMacro.hx | 67 ++++++ source/funkin/ui/credits/CreditsState.hx | 200 ++++++++++++++++++ source/funkin/ui/mainmenu/MainMenuState.hx | 7 + 10 files changed, 445 insertions(+), 13 deletions(-) create mode 100644 source/funkin/data/JsonFile.hx create mode 100644 source/funkin/ui/credits/CreditsData.hx create mode 100644 source/funkin/ui/credits/CreditsDataHandler.hx create mode 100644 source/funkin/ui/credits/CreditsDataMacro.hx create mode 100644 source/funkin/ui/credits/CreditsState.hx diff --git a/Project.xml b/Project.xml index ffc8382a4..5962b9dd8 100644 --- a/Project.xml +++ b/Project.xml @@ -175,6 +175,7 @@ +
diff --git a/assets b/assets index 5f1726f1b..edccf0421 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 5f1726f1b0c11fc747b7473708cf4e5f28be05f1 +Subproject commit edccf04217c49c730b11c80736e2b2d98a25ee95 diff --git a/source/funkin/data/BaseRegistry.hx b/source/funkin/data/BaseRegistry.hx index 7419d9425..118516bec 100644 --- a/source/funkin/data/BaseRegistry.hx +++ b/source/funkin/data/BaseRegistry.hx @@ -325,12 +325,3 @@ abstract class BaseRegistry & Constructible return ScriptedSong.listScriptClasses(); } - function loadEntryMetadataFile(id:String, ?variation:String):Null + function loadEntryMetadataFile(id:String, ?variation:String):Null { variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}'); @@ -438,7 +438,7 @@ class SongRegistry extends BaseRegistry return {fileName: entryFilePath, contents: rawJson}; } - function loadMusicDataFile(id:String, ?variation:String):Null + function loadMusicDataFile(id:String, ?variation:String):Null { variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var entryFilePath:String = Paths.file('music/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.json'); @@ -456,7 +456,7 @@ class SongRegistry extends BaseRegistry return openfl.Assets.exists(entryFilePath); } - function loadEntryChartFile(id:String, ?variation:String):Null + function loadEntryChartFile(id:String, ?variation:String):Null { variation = variation == null ? Constants.DEFAULT_VARIATION : variation; var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-chart${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}'); diff --git a/source/funkin/ui/credits/CreditsData.hx b/source/funkin/ui/credits/CreditsData.hx new file mode 100644 index 000000000..0f6ea6bcd --- /dev/null +++ b/source/funkin/ui/credits/CreditsData.hx @@ -0,0 +1,26 @@ +package funkin.ui.credits; + +/** + * The members of the Funkin' Crew, organized by their roles. + */ +typedef CreditsData = +{ + var roles:Array; +} + +/** + * The members of a specific role on the Funkin' Crew. + */ +typedef CreditsDataRole = +{ + var roleName:String; + var members:Array; +} + +/** + * A member of a specific person on the Funkin' Crew. + */ +typedef CreditsDataMember = +{ + var fullName:String; +} diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx new file mode 100644 index 000000000..6317dd55d --- /dev/null +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -0,0 +1,130 @@ +package funkin.ui.credits; + +import funkin.data.JsonFile; + +using StringTools; + +@:nullSafety +class CreditsDataHandler +{ + public static final BACKER_PUBLIC_URL:String = 'https://funkin.me/backers'; + + #if HARDCODED_CREDITS + static final CREDITS_DATA_PATH:String = "assets/exclude/data/credits.json"; + #else + static final CREDITS_DATA_PATH:String = "assets/data/credits.json"; + #end + + public static function debugPrint(data:Null):Void + { + if (data == null) + { + trace('CreditsData(NULL)'); + + return; + } + + var roleCount = data.roles.length; + var memberCount = 0; + for (role in data.roles) + { + memberCount += role.members.length; + } + + trace('CreditsData($roleCount roles with $memberCount members)'); + } + + /** + * If for some reason the full credits won't load, + * use this hardcoded data for the original Funkin' Crew. + * + * @return `CreditsData` + */ + public static inline function getFallback():CreditsData + { + return { + roles: [ + { + roleName: 'Founders', + members: [ + {fullName: 'ninjamuffin99'}, + {fullName: 'PhantomArcade'}, + {fullName: 'KawaiSprite'}, + {fullName: 'evilsk8r'}, + ] + } + ] + }; + } + + public static function fetchBackerEntries():Array + { + // TODO: Replace this with a web request. + // We can't just grab the current Kickstarter data and include it in builds, + // because we don't want to deadname people who haven't logged into the portal yet. + // It can be async and paginated for performance! + return ['See the list of backers at $BACKER_PUBLIC_URL.']; + } + + #if HARDCODED_CREDITS + /** + * The data for the credits. + * Hardcoded into game via a macro at compile time. + */ + public static final CREDITS_DATA:Null = #if macro null #else CreditsDataMacro.loadCreditsData() #end; + #else + + /** + * The data for the credits. + * Loaded dynamically from the game folder when needed. + * Nullable because data may fail to parse. + */ + public static var CREDITS_DATA(get, default):Null = null; + + static function get_CREDITS_DATA():Null + { + if (CREDITS_DATA == null) CREDITS_DATA = parseCreditsData(fetchCreditsData()); + + return CREDITS_DATA; + } + + static function fetchCreditsData():funkin.data.JsonFile + { + var rawJson:String = openfl.Assets.getText(CREDITS_DATA_PATH).trim(); + + return { + fileName: CREDITS_DATA_PATH, + contents: rawJson + }; + } + + static function parseCreditsData(file:JsonFile):Null + { + #if !macro + if (file.contents == null) return null; + + var parser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + trace('[CREDITS] Parsing credits data from ${CREDITS_DATA_PATH}'); + parser.fromJson(file.contents, file.fileName); + + if (parser.errors.length > 0) + { + printErrors(parser.errors, file.fileName); + return null; + } + return parser.value; + #else + return null; + #end + } + + static function printErrors(errors:Array, id:String = ''):Void + { + trace('[CREDITS] Failed to parse credits data: ${id}'); + + for (error in errors) + funkin.data.DataError.printError(error); + } + #end +} diff --git a/source/funkin/ui/credits/CreditsDataMacro.hx b/source/funkin/ui/credits/CreditsDataMacro.hx new file mode 100644 index 000000000..c97770eef --- /dev/null +++ b/source/funkin/ui/credits/CreditsDataMacro.hx @@ -0,0 +1,67 @@ +package funkin.ui.credits; + +#if macro +import haxe.macro.Context; +#end + +@:access(funkin.ui.credits.CreditsDataHandler) +class CreditsDataMacro +{ + public static macro function loadCreditsData():haxe.macro.Expr.ExprOf + { + #if !display + trace('Hardcoding credits data...'); + var json = CreditsDataMacro.fetchJSON(); + + if (json == null) + { + Context.info('[WARN] Could not fetch JSON data for credits.', Context.currentPos()); + return macro $v{CreditsDataHandler.getFallback()}; + } + + var creditsData = CreditsDataMacro.parseJSON(json); + + if (creditsData == null) + { + Context.info('[WARN] Could not parse JSON data for credits.', Context.currentPos()); + return macro $v{CreditsDataHandler.getFallback()}; + } + + CreditsDataHandler.debugPrint(creditsData); + return macro $v{creditsData}; + // return macro $v{null}; + #else + // `#if display` is used for code completion. In this case we return + // a minimal value to keep code completion fast. + return macro $v{CreditsDataHandler.getFallback()}; + #end + } + + #if macro + static function fetchJSON():Null + { + return sys.io.File.getContent(CreditsDataHandler.CREDITS_DATA_PATH); + } + + /** + * Parse the JSON data for the credits. + * + * @param json The string data to parse. + * @return The parsed data. + */ + static function parseJSON(json:String):Null + { + try + { + // TODO: Use something with better validation but that still works at macro time. + return haxe.Json.parse(json); + } + catch (e) + { + trace('[ERROR] Failed to parse JSON data for credits.'); + trace(e); + return null; + } + } + #end +} diff --git a/source/funkin/ui/credits/CreditsState.hx b/source/funkin/ui/credits/CreditsState.hx new file mode 100644 index 000000000..1e5965695 --- /dev/null +++ b/source/funkin/ui/credits/CreditsState.hx @@ -0,0 +1,200 @@ +package funkin.ui.credits; + +import flixel.text.FlxText; +import flixel.util.FlxColor; +import funkin.audio.FunkinSound; +import flixel.FlxSprite; +import flixel.group.FlxSpriteGroup; + +/** + * The state used to display the credits scroll. + * AAA studios often fail to credit properly, and we're better than them! + */ +class CreditsState extends MusicBeatState +{ + /** + * The height the credits should start at. + * Make this an instanced variable so it gets set by the constructor. + */ + final STARTING_HEIGHT = FlxG.height; + + /** + * The padding on each side of the screen. + */ + static final SCREEN_PAD = 24; + + /** + * The width of the screen the credits should maximally fill up. + * Make this an instanced variable so it gets set by the constructor. + */ + final FULL_WIDTH = FlxG.width - (SCREEN_PAD * 2); + + /** + * The font to use to display the text. + * To use a font from the `assets` folder, use `Paths.font(...)`. + * Choose something that will render Unicode properly. + */ + static final CREDITS_FONT = 'Arial'; + + /** + * The size of the font. + */ + static final CREDITS_FONT_SIZE = 48; + + static final CREDITS_HEADER_FONT_SIZE = 72; + + /** + * The color of the text itself. + */ + static final CREDITS_FONT_COLOR = FlxColor.WHITE; + + /** + * The color of the text's outline. + */ + static final CREDITS_FONT_STROKE_COLOR = FlxColor.BLACK; + + /** + * The speed the credits scroll at, in pixels per second. + */ + static final CREDITS_SCROLL_BASE_SPEED = 25.0; + + /** + * The speed the credits scroll at while the button is held, in pixels per second. + */ + static final CREDITS_SCROLL_FAST_SPEED = CREDITS_SCROLL_BASE_SPEED * 4.0; + + /** + * The actual sprites and text used to display the credits. + */ + var creditsGroup:FlxSpriteGroup; + + var scrollPaused:Bool = false; + + public function new() + { + super(); + } + + public override function create():Void + { + super.create(); + + // Background + var bg = new FlxSprite(Paths.image('menuDesat')); + bg.scrollFactor.x = 0; + bg.scrollFactor.y = 0; + bg.setGraphicSize(Std.int(FlxG.width)); + bg.updateHitbox(); + bg.x = 0; + bg.y = 0; + bg.visible = true; + bg.color = 0xFFB57EDC; // Lavender + add(bg); + + // TODO: Once we need to display Kickstarter backers, + // make this use a recycled pool so we don't kill peformance. + creditsGroup = new FlxSpriteGroup(); + creditsGroup.x = SCREEN_PAD; + creditsGroup.y = STARTING_HEIGHT; + + buildCreditsGroup(); + + add(creditsGroup); + + // Music + FunkinSound.playMusic('freeplayRandom', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: true, + loop: true + }); + FlxG.sound.music.fadeIn(2, 0, 0.8); + } + + function buildCreditsGroup():Void + { + var y = 0; + + for (role in CreditsDataHandler.CREDITS_DATA.roles) + { + creditsGroup.add(buildCreditsLine(role.roleName, y, true, CreditsSide.Center)); + y += CREDITS_HEADER_FONT_SIZE; + + for (member in role.members) + { + creditsGroup.add(buildCreditsLine(member.fullName, y, false, CreditsSide.Center)); + y += CREDITS_FONT_SIZE; + } + + // Padding between each role. + y += CREDITS_FONT_SIZE * 2; + } + } + + function buildCreditsLine(text:String, yPos:Float, header:Bool, side:CreditsSide = CreditsSide.Center):FlxText + { + // CreditsSide.Center: Full screen width + // CreditsSide.Left: Left half of screen + // CreditsSide.Right: Right half of screen + var xPos = (side == CreditsSide.Right) ? (FULL_WIDTH / 2) : 0; + var width = (side == CreditsSide.Center) ? FULL_WIDTH : (FULL_WIDTH / 2); + var size = header ? CREDITS_HEADER_FONT_SIZE : CREDITS_FONT_SIZE; + + var creditsLine:FlxText = new FlxText(xPos, yPos, width, text); + creditsLine.setFormat(CREDITS_FONT, size, CREDITS_FONT_COLOR, FlxTextAlign.CENTER, FlxTextBorderStyle.OUTLINE, CREDITS_FONT_STROKE_COLOR, true); + + return creditsLine; + } + + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + if (!scrollPaused) + { + // TODO: Replace with whatever the special note button is. + if (controls.ACCEPT || FlxG.keys.pressed.SPACE) + { + // Move the whole group. + creditsGroup.y -= CREDITS_SCROLL_FAST_SPEED * elapsed; + } + else + { + // Move the whole group. + creditsGroup.y -= CREDITS_SCROLL_BASE_SPEED * elapsed; + } + } + + if (controls.BACK || hasEnded()) + { + exit(); + } + else if (controls.PAUSE) + { + scrollPaused = !scrollPaused; + } + } + + function hasEnded():Bool + { + return creditsGroup.y < -creditsGroup.height; + } + + function exit():Void + { + FlxG.switchState(new funkin.ui.mainmenu.MainMenuState()); + } + + public override function destroy():Void + { + super.destroy(); + } +} + +enum CreditsSide +{ + Left; + Center; + Right; +} diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index a8c2039ab..e536554d0 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -117,6 +117,10 @@ class MainMenuState extends MusicBeatState startExitState(() -> new funkin.ui.options.OptionsState()); }); + createMenuItem('options', 'mainmenu/options', function() { + startExitState(() -> new funkin.ui.credits.CreditsState()); + }); + // Reset position of menu items. var spacing = 160; var top = (FlxG.height - (spacing * (menuItems.length - 1))) / 2; @@ -125,6 +129,9 @@ class MainMenuState extends MusicBeatState var menuItem = menuItems.members[i]; menuItem.x = FlxG.width / 2; menuItem.y = top + spacing * i; + menuItem.scrollFactor.x = 0.0; + // This one affects how much the menu items move when you scroll between them. + menuItem.scrollFactor.y = 0.4; } resetCamStuff(); From f1811a8594c79f22447af3a62a81fdfb755a9217 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 27 Mar 2024 17:42:29 -0400 Subject: [PATCH 02/24] Implement Pico pause music --- assets | 2 +- source/funkin/play/PauseSubState.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets b/assets index 8013845e3..8ee8c3bd9 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8013845e331015b40c4cc35230f6d02bd2148d52 +Subproject commit 8ee8c3bd9a828ced8e89c7c924842e859fea9a8c diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index f16aa00d8..ed847402a 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -230,7 +230,7 @@ class PauseSubState extends MusicBeatSubState */ function startPauseMusic():Void { - var pauseMusicPath:String = Paths.music('breakfast$musicSuffix'); + var pauseMusicPath:String = Paths.music('breakfast$musicSuffix/breakfast$musicSuffix'); pauseMusic = FunkinSound.load(pauseMusicPath, true, true); if (pauseMusic == null) From 195f366b6571b5a2dc99d6b2058a6b87b9c65a64 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 27 Mar 2024 17:43:15 -0400 Subject: [PATCH 03/24] Fix an issue where the Random button would crash Freeplay. --- source/funkin/audio/FunkinSound.hx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 6520ff27f..56b36d5df 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -399,10 +399,16 @@ class FunkinSound extends FlxSound implements ICloneable return sound; } + @:nullSafety(Off) public override function destroy():Void { // trace('[FunkinSound] Destroying sound "${this._label}"'); super.destroy(); + if (fadeTween != null) + { + fadeTween.cancel(); + fadeTween = null; + } FlxTween.cancelTweensOf(this); this._label = 'unknown'; } From f4dd11e2a976951355a047d97695d00be9f42b29 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 27 Mar 2024 18:44:59 -0400 Subject: [PATCH 04/24] Update more game audio. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 8ee8c3bd9..46cbc7524 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8ee8c3bd9a828ced8e89c7c924842e859fea9a8c +Subproject commit 46cbc752477fd973960efc658a3c62fd57007afe From 8fc7e82c61cbbcc3aa0b3957b53e449cf7e49e4d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 27 Mar 2024 22:50:53 -0400 Subject: [PATCH 05/24] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 46cbc7524..be892870e 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 46cbc752477fd973960efc658a3c62fd57007afe +Subproject commit be892870e4d4397240d0b47275c4a8259583a942 From c1c2621e1d2412994863360e21701e1faf9823b0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 00:18:39 -0400 Subject: [PATCH 06/24] Fix bug where Bad and Shit didn't count at Notes Hit in the results screen. --- source/funkin/play/PlayState.hx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 6dc41e3f9..1cf69489d 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2568,32 +2568,38 @@ class PlayState extends MusicBeatSubState */ function popUpScore(daNote:NoteSprite, score:Int, daRating:String, healthChange:Float):Void { - vocals.playerVolume = 1; - if (daRating == 'miss') { // If daRating is 'miss', that means we made a mistake and should not continue. - trace('[WARNING] popUpScore judged a note as a miss!'); + FlxG.log.warn('popUpScore judged a note as a miss!'); // TODO: Remove this. comboPopUps.displayRating('miss'); return; } + vocals.playerVolume = 1; + var isComboBreak = false; switch (daRating) { case 'sick': Highscore.tallies.sick += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_SICK_COMBO_BREAK; case 'good': Highscore.tallies.good += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_GOOD_COMBO_BREAK; case 'bad': Highscore.tallies.bad += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_BAD_COMBO_BREAK; case 'shit': Highscore.tallies.shit += 1; + Highscore.tallies.totalNotesHit++; isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK; + default: + FlxG.log.error('Wuh? Buh? Guh? Note hit judgement was $daRating!'); } health += healthChange; From 837fcee98386cb150cb6e633054b4bb3b0900519 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 00:19:57 -0400 Subject: [PATCH 07/24] Fix a bug where 000 would display any time a Bad or Shit is hit (instead of just when a combo break is hit) --- source/funkin/play/PlayState.hx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 1cf69489d..a161c04c5 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2441,7 +2441,8 @@ class PlayState extends MusicBeatSubState if (Highscore.tallies.combo != 0) { // Break the combo. - Highscore.tallies.combo = comboPopUps.displayCombo(0); + if (Highscore.tallies.combo >= 10) comboPopUps.displayCombo(0); + Highscore.tallies.combo = 0; } if (playSound) @@ -2607,18 +2608,18 @@ class PlayState extends MusicBeatSubState if (isComboBreak) { // Break the combo, but don't increment tallies.misses. - Highscore.tallies.combo = comboPopUps.displayCombo(0); + if (Highscore.tallies.combo >= 10) comboPopUps.displayCombo(0); + Highscore.tallies.combo = 0; } else { Highscore.tallies.combo++; - Highscore.tallies.totalNotesHit++; if (Highscore.tallies.combo > Highscore.tallies.maxCombo) Highscore.tallies.maxCombo = Highscore.tallies.combo; } playerStrumline.hitNote(daNote, !isComboBreak); - if (daRating == "sick") + if (daRating == 'sick') { playerStrumline.playNoteSplash(daNote.noteData.getDirection()); } From 5311b043ac81b2b38acbc5e57a24590f537b0a4a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:57:22 -0400 Subject: [PATCH 08/24] Rework credits data structure. --- source/funkin/ui/credits/CreditsData.hx | 16 ++++++++--- .../funkin/ui/credits/CreditsDataHandler.hx | 28 +++++++++++-------- source/funkin/ui/credits/CreditsState.hx | 25 +++++++++++++---- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/source/funkin/ui/credits/CreditsData.hx b/source/funkin/ui/credits/CreditsData.hx index 0f6ea6bcd..bf7f13ad5 100644 --- a/source/funkin/ui/credits/CreditsData.hx +++ b/source/funkin/ui/credits/CreditsData.hx @@ -5,7 +5,7 @@ package funkin.ui.credits; */ typedef CreditsData = { - var roles:Array; + var entries:Array; } /** @@ -13,8 +13,16 @@ typedef CreditsData = */ typedef CreditsDataRole = { - var roleName:String; - var members:Array; + @:optional + var header:String; + + @:optional + @:default([]) + var body:Array; + + @:optional + @:default(false) + var appendBackers:Bool; } /** @@ -22,5 +30,5 @@ typedef CreditsDataRole = */ typedef CreditsDataMember = { - var fullName:String; + var line:String; } diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx index 6317dd55d..f2722ffbf 100644 --- a/source/funkin/ui/credits/CreditsDataHandler.hx +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -24,14 +24,14 @@ class CreditsDataHandler return; } - var roleCount = data.roles.length; - var memberCount = 0; - for (role in data.roles) + var entryCount = data.entries.length; + var lineCount = 0; + for (entry in data.entries) { - memberCount += role.members.length; + lineCount += entry?.body?.length ?? 0; } - trace('CreditsData($roleCount roles with $memberCount members)'); + trace('CreditsData($entryCount entries containing $lineCount lines)'); } /** @@ -43,15 +43,19 @@ class CreditsDataHandler public static inline function getFallback():CreditsData { return { - roles: [ + entries: [ { - roleName: 'Founders', - members: [ - {fullName: 'ninjamuffin99'}, - {fullName: 'PhantomArcade'}, - {fullName: 'KawaiSprite'}, - {fullName: 'evilsk8r'}, + header: 'Founders', + body: [ + {line: 'ninjamuffin99'}, + {line: 'PhantomArcade'}, + {line: 'KawaiSprite'}, + {line: 'evilsk8r'}, ] + }, + { + header: 'Kickstarter Backers', + appendBackers: true } ] }; diff --git a/source/funkin/ui/credits/CreditsState.hx b/source/funkin/ui/credits/CreditsState.hx index 1e5965695..d43e25114 100644 --- a/source/funkin/ui/credits/CreditsState.hx +++ b/source/funkin/ui/credits/CreditsState.hx @@ -116,17 +116,30 @@ class CreditsState extends MusicBeatState { var y = 0; - for (role in CreditsDataHandler.CREDITS_DATA.roles) + for (entry in CreditsDataHandler.CREDITS_DATA.entries) { - creditsGroup.add(buildCreditsLine(role.roleName, y, true, CreditsSide.Center)); - y += CREDITS_HEADER_FONT_SIZE; - - for (member in role.members) + if (entry.header != null) { - creditsGroup.add(buildCreditsLine(member.fullName, y, false, CreditsSide.Center)); + creditsGroup.add(buildCreditsLine(entry.header, y, true, CreditsSide.Center)); + y += CREDITS_HEADER_FONT_SIZE; + } + + for (line in entry?.body ?? []) + { + creditsGroup.add(buildCreditsLine(line.line, y, false, CreditsSide.Center)); y += CREDITS_FONT_SIZE; } + if (entry.appendBackers) + { + var backers = CreditsDataHandler.fetchBackerEntries(); + for (backer in backers) + { + creditsGroup.add(buildCreditsLine(backer, y, false, CreditsSide.Center)); + y += CREDITS_FONT_SIZE; + } + } + // Padding between each role. y += CREDITS_FONT_SIZE * 2; } From 3a86b47292b88674dae074f22d8b5d37b9671348 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:57:51 -0400 Subject: [PATCH 09/24] Fix issue where main menu music wouldn't play after credits. --- source/funkin/ui/mainmenu/MainMenuState.hx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index e536554d0..02632628f 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -51,10 +51,7 @@ class MainMenuState extends MusicBeatState transIn = FlxTransitionableState.defaultTransIn; transOut = FlxTransitionableState.defaultTransOut; - if (!(FlxG?.sound?.music?.playing ?? false)) - { - playMenuMusic(); - } + playMenuMusic(); persistentUpdate = persistentDraw = true; @@ -109,15 +106,18 @@ class MainMenuState extends MusicBeatState }); #if CAN_OPEN_LINKS + // In order to prevent popup blockers from triggering, + // we need to open the link as an immediate result of a keypress event, + // so we can't wait for the flicker animation to complete. var hasPopupBlocker = #if web true #else false #end; - createMenuItem('donate', 'mainmenu/donate', selectDonate, hasPopupBlocker); + createMenuItem('merch', 'mainmenu/merch', selectMerch, hasPopupBlocker); #end createMenuItem('options', 'mainmenu/options', function() { startExitState(() -> new funkin.ui.options.OptionsState()); }); - createMenuItem('options', 'mainmenu/options', function() { + createMenuItem('credits', 'mainmenu/credits', function() { startExitState(() -> new funkin.ui.credits.CreditsState()); }); @@ -219,6 +219,11 @@ class MainMenuState extends MusicBeatState { WindowUtil.openURL(Constants.URL_ITCH); } + + function selectMerch() + { + WindowUtil.openURL(Constants.URL_MERCH); + } #end #if newgrounds From 3d14024fd8747d704910570f66a3592a8042e520 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:58:08 -0400 Subject: [PATCH 10/24] Implement merch link. --- source/funkin/util/Constants.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index c7bc03139..7ea537935 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -59,6 +59,11 @@ class Constants */ // ============================== + /** + * Link to buy merch for the game. + */ + public static final URL_MERCH:String = 'https://needlejuicerecords.com/pages/friday-night-funkin'; + /** * Link to download the game on Itch.io. */ From e5eca37dc067e82d3a75f849fd62a8c24fe67dca Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 02:58:46 -0400 Subject: [PATCH 11/24] Update assets submodule. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index edccf0421..289810289 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit edccf04217c49c730b11c80736e2b2d98a25ee95 +Subproject commit 289810289d66cbaf5d55494e396e71bdf9085b1e From c7d67b46e0089a1a1ddfb81bbb470f3100a1b88a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 20:29:32 -0400 Subject: [PATCH 12/24] Update art submodule --- art | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/art b/art index 00463685f..03e7c2a23 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit 00463685fa570f0c853d08e250b46ef80f30bc48 +Subproject commit 03e7c2a2353b184e45955c96d763b7cdf1acbc34 From 1c9b087f2ff6a597255311064f0e576565491d18 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 28 Mar 2024 21:20:08 -0400 Subject: [PATCH 13/24] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 485243fdd..65e6ff18c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 485243fdd44acbc4db6a97ec7bf10a8b18350be9 +Subproject commit 65e6ff18c7fcbd646ac7a3676ca5c2baa95b5fea From 7c04630bb775161e9878e6554146a313aaab5c2a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 00:49:02 -0400 Subject: [PATCH 14/24] Fix a bug where duplicate notes would get placed at the beginning --- source/funkin/play/notes/Strumline.hx | 5 +++++ source/funkin/ui/transition/LoadingState.hx | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index 9a6699c43..a3b5dafc5 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -295,6 +295,11 @@ class Strumline extends FlxSpriteGroup { if (noteData.length == 0) return; + // Ensure note data gets reset if the song happens to loop. + // NOTE: I had to remove this line because it was causing notes visible during the countdown to be placed multiple times. + // I don't remember what bug I was trying to fix by adding this. + // if (conductorInUse.currentStep == 0) nextNoteIndex = 0; + var songStart:Float = PlayState.instance?.startTimestamp ?? 0.0; var hitWindowStart:Float = Conductor.instance.songPosition - Constants.HIT_WINDOW_MS; var renderWindowStart:Float = Conductor.instance.songPosition + RENDER_DISTANCE_MS; diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx index 980c264e3..d913b8099 100644 --- a/source/funkin/ui/transition/LoadingState.hx +++ b/source/funkin/ui/transition/LoadingState.hx @@ -210,7 +210,8 @@ class LoadingState extends MusicBeatState } // Load and cache the song's charts. - if (params?.targetSong != null) + // Don't do this if we already provided the music and charts. + if (params?.targetSong != null && !params.overrideMusic) { params.targetSong.cacheCharts(true); } From 28462681b2af4a55c82fb60aa55b51ac4ab29966 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 00:52:20 -0400 Subject: [PATCH 15/24] Fix bug where 100ms sustains wouldn't update their rendering. --- source/funkin/play/notes/Strumline.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index a3b5dafc5..2b10c05ee 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -827,7 +827,7 @@ class Strumline extends FlxSpriteGroup { // The note sprite pool is full and all note splashes are active. // We have to create a new note. - result = new SustainTrail(0, 100, noteStyle); + result = new SustainTrail(0, 0, noteStyle); this.holdNotes.add(result); } From f50c1ce86fb38d5f5b95a864ed7e0de684414b70 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 10:17:16 -0400 Subject: [PATCH 16/24] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 65e6ff18c..0965a86e2 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 65e6ff18c7fcbd646ac7a3676ca5c2baa95b5fea +Subproject commit 0965a86e2248bd9b8b2387f8b4f6b16385499db0 From 5be47e6619aa13ca6251c1c580d9dbc4ef330818 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 29 Mar 2024 10:34:59 -0400 Subject: [PATCH 17/24] Fix limo ride too --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 0965a86e2..5d78b0705 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0965a86e2248bd9b8b2387f8b4f6b16385499db0 +Subproject commit 5d78b070535d6a1d88c5b450fc092eb6cd331f78 From 846df8de6fa3f207cc4a12cfa175215679c833ea Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 30 Mar 2024 03:06:39 -0400 Subject: [PATCH 18/24] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 5d78b0705..3b168f7ca 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 5d78b070535d6a1d88c5b450fc092eb6cd331f78 +Subproject commit 3b168f7cac41e1843de9a223453d0ff4c04b0283 From 3637e3594ba85e1e0344ab33053b8960edd86b3b Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 30 Mar 2024 03:24:30 -0400 Subject: [PATCH 19/24] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 15c3f16c7..200658724 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 15c3f16c7ec162b7c8d86421b624d74501b9616f +Subproject commit 200658724592b298f49b13016f2c706c54ad538f From fe498b38e51babb076a1a94003be002dc17ac2fe Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 30 Mar 2024 03:32:17 -0400 Subject: [PATCH 20/24] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 2a0afcd76..763c833cb 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 2a0afcd76a26251dbbebb6901df4651f25a92c23 +Subproject commit 763c833cbcde724d50ff31f5bac9f2ac3d5e61a7 From 1df4a354cb3ac7663f2c43da96e555edec7c6724 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 1 Apr 2024 18:34:26 -0400 Subject: [PATCH 21/24] Freeplay menu now filters to supported songs when you change difficulty --- source/funkin/ui/freeplay/FreeplayState.hx | 70 +++++++++++++++++----- source/funkin/util/Constants.hx | 6 ++ 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 6cb0d1d9a..471fe7e28 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -536,21 +536,18 @@ class FreeplayState extends MusicBeatSubState }); } + var currentFilter:SongFilter = null; + var currentFilteredSongs:Array = []; + /** * Given the current filter, rebuild the current song list. * * @param filterStuff A filter to apply to the song list (regex, startswith, all, favorite) * @param force + * @param onlyIfChanged Only apply the filter if the song list has changed */ - public function generateSongList(?filterStuff:SongFilter, force:Bool = false):Void + public function generateSongList(filterStuff:Null, force:Bool = false, onlyIfChanged:Bool = true):Void { - curSelected = 1; - - for (cap in grpCapsules.members) - { - cap.kill(); - } - var tempSongs:Array = songs; if (filterStuff != null) @@ -582,6 +579,35 @@ class FreeplayState extends MusicBeatSubState } } + // Filter further by current selected difficulty. + if (currentDifficulty != null) + { + tempSongs = tempSongs.filter(song -> { + if (song == null) return true; // Random + return song.songDifficulties.contains(currentDifficulty); + }); + } + + if (onlyIfChanged) + { + // == performs equality by reference + if (tempSongs.isEqualUnordered(currentFilteredSongs)) return; + } + + // Only now do we know that the filter is actually changing. + + rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId; + + for (cap in grpCapsules.members) + { + cap.kill(); + } + + currentFilter = filterStuff; + + currentFilteredSongs = tempSongs; + curSelected = 0; + var hsvShader:HSVShader = new HSVShader(); var randomCapsule:SongMenuItem = grpCapsules.recycle(SongMenuItem); @@ -658,11 +684,12 @@ class FreeplayState extends MusicBeatSubState if (FlxG.keys.justPressed.F) { - if (songs[curSelected] != null) + var targetSong = grpCapsules.members[curSelected]?.songData; + if (targetSong != null) { var realShit:Int = curSelected; - songs[curSelected].isFav = !songs[curSelected].isFav; - if (songs[curSelected].isFav) + targetSong.isFav = !targetSong.isFav; + if (targetSong.isFav) { FlxTween.tween(grpCapsules.members[realShit], {angle: 360}, 0.4, { @@ -854,11 +881,13 @@ class FreeplayState extends MusicBeatSubState { dj.resetAFKTimer(); changeDiff(-1); + generateSongList(currentFilter, true); } if (controls.UI_RIGHT_P && !FlxG.keys.pressed.CONTROL) { dj.resetAFKTimer(); changeDiff(1); + generateSongList(currentFilter, true); } if (controls.BACK && !typing.hasFocus) @@ -926,7 +955,7 @@ class FreeplayState extends MusicBeatSubState public override function destroy():Void { super.destroy(); - var daSong:Null = songs[curSelected]; + var daSong:Null = grpCapsules.members[curSelected]?.songData; if (daSong != null) { clearDaCache(daSong.songName); @@ -948,10 +977,10 @@ class FreeplayState extends MusicBeatSubState currentDifficulty = diffIdsCurrent[currentDifficultyIndex]; - var daSong:Null = songs[curSelected]; + var daSong:Null = grpCapsules.members[curSelected].songData; if (daSong != null) { - var songScore:SaveScoreData = Save.instance.getSongScore(songs[curSelected].songId, currentDifficulty); + var songScore:SaveScoreData = Save.instance.getSongScore(grpCapsules.members[curSelected].songData.songId, currentDifficulty); intendedScore = songScore?.score ?? 0; intendedCompletion = songScore?.accuracy ?? 0.0; rememberedDifficulty = currentDifficulty; @@ -1103,6 +1132,12 @@ class FreeplayState extends MusicBeatSubState targetVariation: targetVariation, practiceMode: false, minimalMode: false, + + #if (debug || FORCE_DEBUG_VERSION) + botPlayMode: FlxG.keys.pressed.SHIFT, + #else + botPlayMode: false, + #end // TODO: Make these an option! It's currently only accessible via chart editor. // startTimestamp: 0.0, // playbackRate: 0.5, @@ -1115,10 +1150,12 @@ class FreeplayState extends MusicBeatSubState { if (rememberedSongId != null) { - curSelected = songs.findIndex(function(song) { + curSelected = currentFilteredSongs.findIndex(function(song) { if (song == null) return false; return song.songId == rememberedSongId; }); + + if (curSelected == -1) curSelected = 0; } if (rememberedDifficulty != null) @@ -1127,7 +1164,7 @@ class FreeplayState extends MusicBeatSubState } // Set the difficulty star count on the right. - var daSong:Null = songs[curSelected]; + var daSong:Null = grpCapsules.members[curSelected]?.songData; albumRoll.setDifficultyStars(daSong?.songRating ?? 0); } @@ -1156,6 +1193,7 @@ class FreeplayState extends MusicBeatSubState { intendedScore = 0; intendedCompletion = 0.0; + diffIdsCurrent = diffIdsTotal; rememberedSongId = null; rememberedDifficulty = null; } diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 5d355f2da..13a6f65b5 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -181,6 +181,12 @@ class Constants */ public static final DEFAULT_DIFFICULTY_LIST:Array = ['easy', 'normal', 'hard']; + /** + * List of all difficulties used by the base game. + * Includes Erect and Nightmare. + */ + public static final DEFAULT_DIFFICULTY_LIST_FULL:Array = ['easy', 'normal', 'hard', 'erect', 'nightmare']; + /** * Default player character for charts. */ From 927b2a7cfc5ef956e77aae1a7dd7660f8d9a738a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 1 Apr 2024 13:05:16 -0400 Subject: [PATCH 22/24] Put judgements below the notes, and remove COMBO word. --- source/funkin/play/PlayState.hx | 6 ++++-- source/funkin/play/components/PopUpStuff.hx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 274ee4fe8..97dd96016 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -728,6 +728,10 @@ class PlayState extends MusicBeatSubState #end initialized = true; + + // This step ensures z-indexes are applied properly, + // and it's important to call it last so all elements get affected. + refresh(); } public override function draw():Void @@ -1720,8 +1724,6 @@ class PlayState extends MusicBeatSubState playerStrumline.fadeInArrows(); opponentStrumline.fadeInArrows(); } - - this.refresh(); } /** diff --git a/source/funkin/play/components/PopUpStuff.hx b/source/funkin/play/components/PopUpStuff.hx index 39fc192a0..724bf0cb9 100644 --- a/source/funkin/play/components/PopUpStuff.hx +++ b/source/funkin/play/components/PopUpStuff.hx @@ -85,7 +85,7 @@ class PopUpStuff extends FlxTypedGroup comboSpr.velocity.y -= 150; comboSpr.velocity.x += FlxG.random.int(1, 10); - add(comboSpr); + // add(comboSpr); if (PlayState.instance.currentStageId.startsWith('school')) { From 67e096e4430a84bac3e04da02fe249240866c7e0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 1 Apr 2024 21:59:53 -0400 Subject: [PATCH 23/24] Bunch of results screen fixes --- source/funkin/Highscore.hx | 4 ++ source/funkin/play/PauseSubState.hx | 2 + source/funkin/play/PlayState.hx | 43 +++++++++--- source/funkin/play/ResultState.hx | 68 +++++++++++++------ source/funkin/play/components/TallyCounter.hx | 23 +++++-- source/funkin/ui/freeplay/FreeplayState.hx | 4 +- 6 files changed, 106 insertions(+), 38 deletions(-) diff --git a/source/funkin/Highscore.hx b/source/funkin/Highscore.hx index 996e2367e..94f41cea4 100644 --- a/source/funkin/Highscore.hx +++ b/source/funkin/Highscore.hx @@ -59,6 +59,7 @@ abstract Tallies(RawTallies) totalNotes: 0, totalNotesHit: 0, maxCombo: 0, + score: 0, isNewHighscore: false } } @@ -81,6 +82,9 @@ typedef RawTallies = var good:Int; var sick:Int; var maxCombo:Int; + + var score:Int; + var isNewHighscore:Bool; /** diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index ed847402a..2af04749f 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -567,6 +567,8 @@ class PauseSubState extends MusicBeatSubState PlayStatePlaylist.campaignDifficulty = difficulty; PlayState.instance.currentDifficulty = PlayStatePlaylist.campaignDifficulty; + FreeplayState.rememberedDifficulty = difficulty; + PlayState.instance.needsReset = true; state.close(); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 274ee4fe8..438941f90 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2731,7 +2731,7 @@ class PlayState extends MusicBeatSubState */ public function endSong(rightGoddamnNow:Bool = false):Void { - FlxG.sound.music.volume = 0; + if (FlxG.sound.music != null) FlxG.sound.music.volume = 0; vocals.volume = 0; mayPauseGame = false; @@ -2749,6 +2749,8 @@ class PlayState extends MusicBeatSubState deathCounter = 0; + var isNewHighscore = false; + if (currentSong != null && currentSong.validScore) { // crackhead double thingie, sets whether was new highscore, AND saves the song! @@ -2779,11 +2781,14 @@ class PlayState extends MusicBeatSubState #if newgrounds NGio.postScore(score, currentSong.id); #end + isNewHighscore = true; } } if (PlayStatePlaylist.isStoryMode) { + isNewHighscore = false; + PlayStatePlaylist.campaignScore += songScore; // Pop the next song ID from the list. @@ -2833,6 +2838,7 @@ class PlayState extends MusicBeatSubState #if newgrounds NGio.postScore(score, 'Level ${PlayStatePlaylist.campaignId}'); #end + isNewHighscore = true; } } @@ -2844,11 +2850,11 @@ class PlayState extends MusicBeatSubState { if (rightGoddamnNow) { - moveToResultsScreen(); + moveToResultsScreen(isNewHighscore); } else { - zoomIntoResultsScreen(); + zoomIntoResultsScreen(isNewHighscore); } } } @@ -2909,11 +2915,11 @@ class PlayState extends MusicBeatSubState { if (rightGoddamnNow) { - moveToResultsScreen(); + moveToResultsScreen(isNewHighscore); } else { - zoomIntoResultsScreen(); + zoomIntoResultsScreen(isNewHighscore); } } } @@ -2987,7 +2993,7 @@ class PlayState extends MusicBeatSubState /** * Play the camera zoom animation and then move to the results screen once it's done. */ - function zoomIntoResultsScreen():Void + function zoomIntoResultsScreen(isNewHighscore:Bool):Void { trace('WENT TO RESULTS SCREEN!'); @@ -3044,7 +3050,7 @@ class PlayState extends MusicBeatSubState { ease: FlxEase.expoIn, onComplete: function(_) { - moveToResultsScreen(); + moveToResultsScreen(isNewHighscore); } }); }); @@ -3053,7 +3059,7 @@ class PlayState extends MusicBeatSubState /** * Move to the results screen right goddamn now. */ - function moveToResultsScreen():Void + function moveToResultsScreen(isNewHighscore:Bool):Void { persistentUpdate = false; vocals.stop(); @@ -3065,7 +3071,24 @@ class PlayState extends MusicBeatSubState { storyMode: PlayStatePlaylist.isStoryMode, title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), - tallies: talliesToUse, + scoreData: + { + score: songScore, + tallies: + { + sick: Highscore.tallies.sick, + good: Highscore.tallies.good, + bad: Highscore.tallies.bad, + shit: Highscore.tallies.shit, + missed: Highscore.tallies.missed, + combo: Highscore.tallies.combo, + maxCombo: Highscore.tallies.maxCombo, + totalNotesHit: Highscore.tallies.totalNotesHit, + totalNotes: Highscore.tallies.totalNotes, + }, + accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, + }, + isNewHighscore: isNewHighscore }); res.camera = camHUD; openSubState(res); @@ -3212,7 +3235,7 @@ class PlayState extends MusicBeatSubState // Don't go back in time to before the song started. targetTimeMs = Math.max(0, targetTimeMs); - FlxG.sound.music.time = targetTimeMs; + if (FlxG.sound.music != null) FlxG.sound.music.time = targetTimeMs; handleSkippedNotes(); SongEventRegistry.handleSkippedEvents(songEvents, Conductor.instance.songPosition); diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 821f4ba3c..7dbaf087f 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -1,5 +1,6 @@ package funkin.play; +import funkin.util.MathUtil; import funkin.ui.story.StoryMenuState; import funkin.graphics.adobeanimate.FlxAtlasSprite; import flixel.FlxSprite; @@ -16,6 +17,8 @@ import flixel.tweens.FlxTween; import funkin.audio.FunkinSound; import flixel.util.FlxGradient; import flixel.util.FlxTimer; +import funkin.save.Save; +import funkin.save.Save.SaveScoreData; import funkin.graphics.shaders.LeftMaskShader; import funkin.play.components.TallyCounter; @@ -42,12 +45,15 @@ class ResultState extends MusicBeatSubState override function create():Void { - if (params.tallies.sick == params.tallies.totalNotesHit - && params.tallies.maxCombo == params.tallies.totalNotesHit) resultsVariation = PERFECT; - else if (params.tallies.missed + params.tallies.bad + params.tallies.shit >= params.tallies.totalNotes * 0.50) - resultsVariation = SHIT; // if more than half of your song was missed, bad, or shit notes, you get shit ending! - else - resultsVariation = NORMAL; + /* + if (params.scoreData.sick == params.scoreData.totalNotesHit + && params.scoreData.maxCombo == params.scoreData.totalNotesHit) resultsVariation = PERFECT; + else if (params.scoreData.missed + params.scoreData.bad + params.scoreData.shit >= params.scoreData.totalNotes * 0.50) + resultsVariation = SHIT; // if more than half of your song was missed, bad, or shit notes, you get shit ending! + else + resultsVariation = NORMAL; + */ + resultsVariation = NORMAL; FunkinSound.playMusic('results$resultsVariation', { @@ -130,12 +136,16 @@ class ResultState extends MusicBeatSubState var diffSpr:String = switch (PlayState.instance.currentDifficulty) { - case 'EASY': + case 'easy': 'difEasy'; - case 'NORMAL': + case 'normal': 'difNormal'; - case 'HARD': + case 'hard': 'difHard'; + case 'erect': + 'difErect'; + case 'nightmare': + 'difNightmare'; case _: 'difNormal'; } @@ -195,29 +205,33 @@ class ResultState extends MusicBeatSubState * 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); + var totalHit:TallyCounter = new TallyCounter(375, hStuf * 3, params.scoreData.tallies.totalNotesHit); ratingGrp.add(totalHit); - var maxCombo:TallyCounter = new TallyCounter(375, hStuf * 4, params.tallies.maxCombo); + var maxCombo:TallyCounter = new TallyCounter(375, hStuf * 4, params.scoreData.tallies.maxCombo); ratingGrp.add(maxCombo); hStuf += 2; var extraYOffset:Float = 5; - var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, params.tallies.sick, 0xFF89E59E); + var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, params.scoreData.tallies.sick, 0xFF89E59E); ratingGrp.add(tallySick); - var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, params.tallies.good, 0xFF89C9E5); + var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, params.scoreData.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.scoreData.tallies.bad, 0xFFE6CF8A); ratingGrp.add(tallyBad); - var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, params.tallies.shit, 0xFFE68C8A); + var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, params.scoreData.tallies.shit, 0xFFE68C8A); ratingGrp.add(tallyShit); - var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.tallies.missed, 0xFFC68AE6); + var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.scoreData.tallies.missed, 0xFFC68AE6); ratingGrp.add(tallyMissed); + var score:TallyCounter = new TallyCounter(825, 630, params.scoreData.score, RIGHT); + score.scale.set(2, 2); + ratingGrp.add(score); + for (ind => rating in ratingGrp.members) { rating.visible = false; @@ -235,9 +249,16 @@ class ResultState extends MusicBeatSubState scorePopin.animation.play("score"); scorePopin.visible = true; - highscoreNew.visible = true; - highscoreNew.animation.play("new"); - FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); + if (params.isNewHighscore) + { + highscoreNew.visible = true; + highscoreNew.animation.play("new"); + FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); + } + else + { + highscoreNew.visible = false; + } }; switch (resultsVariation) @@ -276,8 +297,6 @@ class ResultState extends MusicBeatSubState } }); - if (params.tallies.isNewHighscore) trace("ITS A NEW HIGHSCORE!!!"); - super.create(); } @@ -393,8 +412,13 @@ typedef ResultsStateParams = */ var title:String; + /** + * Whether the displayed score is a new highscore + */ + var isNewHighscore:Bool; + /** * The score, accuracy, and judgements. */ - var tallies:Highscore.Tallies; + var scoreData:SaveScoreData; }; diff --git a/source/funkin/play/components/TallyCounter.hx b/source/funkin/play/components/TallyCounter.hx index 77e6ef4ec..35a8f3f51 100644 --- a/source/funkin/play/components/TallyCounter.hx +++ b/source/funkin/play/components/TallyCounter.hx @@ -6,6 +6,8 @@ import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.math.FlxMath; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; +import flixel.text.FlxText.FlxTextAlign; +import funkin.util.MathUtil; /** * Numerical counters used next to each judgement in the Results screen. @@ -13,18 +15,23 @@ import flixel.tweens.FlxTween; class TallyCounter extends FlxTypedSpriteGroup { public var curNumber:Float = 0; - public var neededNumber:Int = 0; + public var flavour:Int = 0xFFFFFFFF; - public function new(x:Float, y:Float, neededNumber:Int = 0, ?flavour:Int = 0xFFFFFFFF) + public var align:FlxTextAlign = FlxTextAlign.LEFT; + + public function new(x:Float, y:Float, neededNumber:Int = 0, ?flavour:Int = 0xFFFFFFFF, align:FlxTextAlign = FlxTextAlign.LEFT) { super(x, y); + this.align = align; + this.flavour = flavour; this.neededNumber = neededNumber; - drawNumbers(); + + if (curNumber == neededNumber) drawNumbers(); } var tmr:Float = 0; @@ -41,6 +48,8 @@ class TallyCounter extends FlxTypedSpriteGroup var seperatedScore:Array = []; var tempCombo:Int = Math.round(curNumber); + var fullNumberDigits:Int = Std.int(Math.max(1, Math.ceil(MathUtil.logBase(10, neededNumber)))); + while (tempCombo != 0) { seperatedScore.push(tempCombo % 10); @@ -55,7 +64,13 @@ class TallyCounter extends FlxTypedSpriteGroup { if (ind >= members.length) { - var numb:TallyNumber = new TallyNumber(ind * 43, 0, num); + var xPos = ind * (43 * this.scale.x); + if (this.align == FlxTextAlign.RIGHT) + { + xPos -= (fullNumberDigits * (43 * this.scale.x)); + } + var numb:TallyNumber = new TallyNumber(xPos, 0, num); + numb.scale.set(this.scale.x, this.scale.y); add(numb); numb.color = flavour; } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 6cb0d1d9a..058f61a5b 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -133,8 +133,8 @@ class FreeplayState extends MusicBeatSubState var stickerSubState:StickerSubState; - static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; - static var rememberedSongId:Null = null; + public static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; + public static var rememberedSongId:Null = null; public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { From 626cc5cc78d6543fae7b1095049e97609c2e9f59 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 1 Apr 2024 22:06:44 -0400 Subject: [PATCH 24/24] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index b2144938c..d7e85ef60 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit b2144938c899e4a5d2d05466f710aa75ff4e1d1c +Subproject commit d7e85ef60933ca93d47e1db6295aba8aa64fcbdf