From 1b6febf01c9a7826ec65004d3d4e46780792116f Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 18 Apr 2024 20:23:03 -0400 Subject: [PATCH 001/131] initial freeplay songs loading --- Project.xml | 1 + checkstyle.json | 2 +- hmm.json | 9 +- source/funkin/Paths.hx | 20 ++++- source/funkin/audio/FunkinSound.hx | 97 ++++++++++++++++++++-- source/funkin/ui/freeplay/FreeplayState.hx | 23 +++-- 6 files changed, 127 insertions(+), 25 deletions(-) diff --git a/Project.xml b/Project.xml index fcfcfb9f..87608bb8 100644 --- a/Project.xml +++ b/Project.xml @@ -126,6 +126,7 @@ + diff --git a/checkstyle.json b/checkstyle.json index dc89409d..41f0a799 100644 --- a/checkstyle.json +++ b/checkstyle.json @@ -79,7 +79,7 @@ { "props": { "ignoreExtern": true, - "format": "^[a-z][A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$", + "format": "^[a-zA-Z0-9]+(?:_[a-zA-Z0-9]+)*$", "tokens": ["INLINE", "NOTINLINE"] }, "type": "ConstantName" diff --git a/hmm.json b/hmm.json index a6e4467a..6b119c52 100644 --- a/hmm.json +++ b/hmm.json @@ -1,5 +1,12 @@ { "dependencies": [ + { + "name": "FlxPartialSound", + "type": "git", + "dir": null, + "ref": "main", + "url": "https://github.com/FunkinCrew/FlxPartialSound.git" + }, { "name": "discord_rpc", "type": "git", @@ -171,4 +178,4 @@ "url": "https://github.com/FunkinCrew/thx.semver" } ] -} +} \ No newline at end of file diff --git a/source/funkin/Paths.hx b/source/funkin/Paths.hx index 54a4b7ac..b0a97c4f 100644 --- a/source/funkin/Paths.hx +++ b/source/funkin/Paths.hx @@ -123,9 +123,17 @@ class Paths return 'songs:assets/songs/${song.toLowerCase()}/Voices$suffix.${Constants.EXT_SOUND}'; } - public static function inst(song:String, ?suffix:String = ''):String + /** + * Gets the path to an `Inst.mp3/ogg` song instrumental from songs:assets/songs/`song`/ + * @param song name of the song to get instrumental for + * @param suffix any suffix to add to end of song name, used for `-erect` variants usually + * @param withExtension if it should return with the audio file extension `.mp3` or `.ogg`. + * @return String + */ + public static function inst(song:String, ?suffix:String = '', ?withExtension:Bool = true):String { - return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix.${Constants.EXT_SOUND}'; + var ext:String = withExtension ? '.${Constants.EXT_SOUND}' : ''; + return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix$ext'; } public static function image(key:String, ?library:String):String @@ -153,3 +161,11 @@ class Paths return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library)); } } + +enum abstract PathsFunction(String) +{ + var MUSIC; + var INST; + var VOICES; + var SOUND; +} diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index df05cc3e..728a06a3 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -11,7 +11,11 @@ import funkin.audio.waveform.WaveformDataParser; import funkin.data.song.SongData.SongMusicData; import funkin.data.song.SongRegistry; import funkin.util.tools.ICloneable; +import funkin.util.flixel.sound.FlxPartialSound; +import funkin.Paths.PathsFunction; import openfl.Assets; +import lime.app.Future; +import lime.app.Promise; import openfl.media.SoundMixer; #if (openfl >= "8.0.0") import openfl.utils.AssetType; @@ -342,20 +346,52 @@ class FunkinSound extends FlxSound implements ICloneable FlxG.log.warn('Tried and failed to find music metadata for $key'); } } - - var music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, params.loop ?? true, false, true); - if (music != null) + var pathsFunction = params.pathsFunction ?? MUSIC; + var pathToUse = switch (pathsFunction) { - FlxG.sound.music = music; + case MUSIC: Paths.music('$key/$key'); + case INST: Paths.inst('$key'); + default: Paths.music('$key/$key'); + } - // Prevent repeat update() and onFocus() calls. - FlxG.sound.list.remove(FlxG.sound.music); + var shouldLoadPartial = params.partialParams?.loadPartial ?? false; - return true; + if (shouldLoadPartial) + { + var music = FunkinSound.loadPartial(pathToUse, params.partialParams?.start ?? 0, params.partialParams?.end ?? 1, params?.startingVolume ?? 1.0, + params.loop ?? true, false, true); + + if (music != null) + { + music.onComplete(function(partialMusic:Null) { + @:nullSafety(Off) + FlxG.sound.music = partialMusic; + FlxG.sound.list.remove(FlxG.sound.music); + }); + + return true; + } + else + { + return false; + } } else { - return false; + var music = FunkinSound.load(pathToUse, params?.startingVolume ?? 1.0, params.loop ?? true, false, true); + if (music != null) + { + FlxG.sound.music = music; + + // Prevent repeat update() and onFocus() calls. + FlxG.sound.list.remove(FlxG.sound.music); + + return true; + } + else + { + return false; + } } } @@ -415,6 +451,36 @@ class FunkinSound extends FlxSound implements ICloneable return sound; } + /** + * Will load a section of a sound file, useful for Freeplay where we don't want to load all the bytes of a song + * @param path The path to the sound file + * @param start The start time of the sound file + * @param end The end time of the sound file + * @param volume Volume to start at + * @param looped Whether the sound file should loop + * @param autoDestroy Whether the sound file should be destroyed after it finishes playing + * @param autoPlay Whether the sound file should play immediately + * @return A FunkinSound object + */ + public static function loadPartial(path:String, start:Float = 0, end:Float = 1, volume:Float = 1.0, looped:Bool = false, autoDestroy:Bool = false, + autoPlay:Bool = true, ?onComplete:Void->Void, ?onLoad:Void->Void):Future> + { + var promise:lime.app.Promise> = new lime.app.Promise>(); + + // split the path and get only after first : + // we are bypassing the openfl/lime asset library fuss + path = Paths.stripLibrary(path); + + var soundRequest = FlxPartialSound.partialLoadFromFile(path, start, end); + + soundRequest.onComplete(function(partialSound) { + var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad); + promise.complete(snd); + }); + + return promise.future; + } + @:nullSafety(Off) public override function destroy():Void { @@ -498,4 +564,19 @@ typedef FunkinSoundPlayMusicParams = * @default `true` */ var ?mapTimeChanges:Bool; + + /** + * Which Paths function to use to load a song + * @default `MUSIC` + */ + var ?pathsFunction:PathsFunction; + + var ?partialParams:PartialSoundParams; +} + +typedef PartialSoundParams = +{ + var loadPartial:Bool; + var start:Float; + var end:Float; } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 7b754384..c290e655 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1244,22 +1244,19 @@ class FreeplayState extends MusicBeatSubState else { // TODO: Stream the instrumental of the selected song? - var didReplace:Bool = FunkinSound.playMusic('freakyMenu', + FunkinSound.playMusic(daSongCapsule.songData.songId, { - startingVolume: 0.0, + startingVolume: 0.5, overrideExisting: true, - restartTrack: false + restartTrack: false, + pathsFunction: INST, + partialParams: + { + loadPartial: true, + start: 0, + end: 0.1 + } }); - if (didReplace) - { - FunkinSound.playMusic('freakyMenu', - { - startingVolume: 0.0, - overrideExisting: true, - restartTrack: false - }); - FlxG.sound.music.fadeIn(2, 0, 0.8); - } } grpCapsules.members[curSelected].selected = true; } From f2a06ad37b79c76566ab62f8244a84ac864155a0 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 9 May 2024 01:56:52 -0400 Subject: [PATCH 002/131] fading in and erect track loading --- source/funkin/audio/FunkinSound.hx | 14 ++++++++++++-- source/funkin/ui/freeplay/FreeplayState.hx | 9 +++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 728a06a3..5a49e29e 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -347,10 +347,11 @@ class FunkinSound extends FlxSound implements ICloneable } } var pathsFunction = params.pathsFunction ?? MUSIC; + var suffix = params.suffix ?? ''; var pathToUse = switch (pathsFunction) { case MUSIC: Paths.music('$key/$key'); - case INST: Paths.inst('$key'); + case INST: Paths.inst('$key', suffix); default: Paths.music('$key/$key'); } @@ -359,7 +360,7 @@ class FunkinSound extends FlxSound implements ICloneable if (shouldLoadPartial) { var music = FunkinSound.loadPartial(pathToUse, params.partialParams?.start ?? 0, params.partialParams?.end ?? 1, params?.startingVolume ?? 1.0, - params.loop ?? true, false, true); + params.loop ?? true, false, true, params.onComplete, params.onLoad); if (music != null) { @@ -541,6 +542,12 @@ typedef FunkinSoundPlayMusicParams = */ var ?startingVolume:Float; + /** + * The suffix of the music file to play. Usually for "-erect" tracks when loading an INST file + * @default `` + */ + var ?suffix:String; + /** * Whether to override music if a different track is already playing. * @default `false` @@ -572,6 +579,9 @@ typedef FunkinSoundPlayMusicParams = var ?pathsFunction:PathsFunction; var ?partialParams:PartialSoundParams; + + var ?onComplete:Void->Void; + var ?onLoad:Void->Void; } typedef PartialSoundParams = diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index c290e655..d0183bf8 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1243,19 +1243,24 @@ class FreeplayState extends MusicBeatSubState } else { + var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; // TODO: Stream the instrumental of the selected song? FunkinSound.playMusic(daSongCapsule.songData.songId, { - startingVolume: 0.5, + startingVolume: 0.0, overrideExisting: true, restartTrack: false, pathsFunction: INST, + suffix: potentiallyErect, partialParams: { loadPartial: true, start: 0, end: 0.1 - } + }, + onLoad: function() { + FlxG.sound.music.fadeIn(2, 0, 0.4); + } }); } grpCapsules.members[curSelected].selected = true; From 6fc5e8cc2f7e5c9855be1950a75be6b0c4c15c05 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 9 May 2024 22:36:39 -0400 Subject: [PATCH 003/131] Fixed up some metadata --- example_mods/introMod/_polymod_meta.json | 2 +- example_mods/testing123/_polymod_meta.json | 2 +- tests/unit/assets/shared/images/arrows.png | Bin 4806 -> 0 bytes tests/unit/assets/shared/images/arrows.xml | 27 --------------------- 4 files changed, 2 insertions(+), 29 deletions(-) delete mode 100644 tests/unit/assets/shared/images/arrows.png delete mode 100644 tests/unit/assets/shared/images/arrows.xml diff --git a/example_mods/introMod/_polymod_meta.json b/example_mods/introMod/_polymod_meta.json index e0b03f1c..4dc0cd80 100644 --- a/example_mods/introMod/_polymod_meta.json +++ b/example_mods/introMod/_polymod_meta.json @@ -3,7 +3,7 @@ "description": "An introductory mod.", "contributors": [ { - "name": "MasterEric" + "name": "EliteMasterEric" } ], "api_version": "0.1.0", diff --git a/example_mods/testing123/_polymod_meta.json b/example_mods/testing123/_polymod_meta.json index 4c0f177f..0a2ed042 100644 --- a/example_mods/testing123/_polymod_meta.json +++ b/example_mods/testing123/_polymod_meta.json @@ -3,7 +3,7 @@ "description": "Newgrounds? More like OLDGROUNDS lol.", "contributors": [ { - "name": "MasterEric" + "name": "EliteMasterEric" } ], "api_version": "0.1.0", diff --git a/tests/unit/assets/shared/images/arrows.png b/tests/unit/assets/shared/images/arrows.png deleted file mode 100644 index a443684327b409e3297d9456cb28afddd889b499..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4806 zcmai2XEYp6yj`pygdov-7k%|!cGXp)6MuaLK|-P>EP||(5G_IU5sY@60Hmk>6#_e#O;P}WCQuimZWfrip8@wZoBrMxN~^)i^X@p2BQX*PrgnR4 zB`_5RX(P^C<+|v4=n}&Oq;pdb3KA044U4U`06wI5QmZ+_)Z1EZ%Hw02Y^tV11u68 zJ2jL>z*K3A!K|AAY9;ySFApP`fNCAt%76>#jpNA`+3`t0;OWgJ2Y%4{3cs4xp9K-X zuk;WPYl|@U`Mev<*fjuFg{H|RxdFzZ(tg_Rs1mR4p3oBo<9BP*w@RjoxDNvHqD)e4 ztURd&;4}cu&0>c1qz7uzQ{<<*-#NJ%1Sf8b2-=4I;YtdehK2P|Jv|g#vP6cxQ9Ih_ z{VR}zOPayta1izIO2I=#USlH(^S1zAUjxAAiRu*jH zCxCb)me;|vmA7-2>pFMT+%!IvbDwODcJQRYbFGGc^ zvkBh)&`1%|@PdkAaWYi%RH0^)6Eo+(T~gk`>;J}$iXP;8L`~2xiS79LUBo42o0kEOhm~wnZWboa@C6=Xu^((8{it zr_`G#e0=cJZxcP838zUT=_ncdWL1-)f*^;y4m@YK*zT&ad(R{d0Z7y60v6 zrRyc}q1A%(sqQXe=gtqNnTM4`4$4MRc6oV{4?4GHS7gfXvW4~pzVdEsd1$Cfuv7y? zP`m?^tW9bzH_~jOMbe_iRfV__Y}^Nc)%A8G>r6}X&N2@Eo*s(N<&46X#O{_U&rCkQ z{MDpKX3Z(#i(qQAFMYBpRB$fD3wZ~56l*pWe%Gw6Olm0nZh_svUBv6$srLaw)Bm{& znlnl~V-w)ikJ=j<7TP9IBEImfm_ZR-4VUZj1TB9w6t@#;&Uf#diLn6rk{Z)C^^v&6-p0DR z^o((zocBd_Gszpl9a`J307h3M4gn7XmGTDeYcwx=eJc;7q`O{oiAc$dTKnEqnzil` zdM2eb&!2F=R2Ke%@UseG_8Ib@?oL`iKDG-wdcG1#9Qw0{hOn^^5}wCs2m?%oI6hz{ zgF2EKr56swk`rJsA5gmqqfT{ji$98)R`xEl|c0K5^zGqE6 zhL;VbcI!OC+F?e*E~)jveC8@jUso~z2_x-S7(YN#5P#B=;`l_-Y>aLBs=> z?(F!MJQzBxUv5QaxGP_QO??*hp>ib4W?wmHTYi>W*qb@?=v-Wx$df=(jb2F!Ii z^hQ?)w04-c)zXlphQ=7s>X3+(PXl-FX9|%YI&z z*yl79kRE>rf0ov!Q$i#Bv*00+U{)+>8TC-CyDA;o-fqFIQN@wxL-> zzkeg2IlF)SK{@{Co`GNEbfYkuCA|_bFdgWuhKeQFU#I~3E4QNl%cE>FdDyw% zfdcLNx50w9CVVSb~ zfJ|kRk^kBy zF=rh1f}TuYBl1Jk*03xJ520y_Q8mC!ex(;~R8Tn8GdEeH7(=Nr{I8mog9?`_T4v_d z=ItzYGTKvv)X;y%t%4jSz*hMp9lS(hgdG6aj}YIACP9sIuvU#HC%_Umma*H@Njv;pJcQO!d0o~nKg>4hVz9969g z6+=2ZPiM&KZZ~;SWvX~;ugM}m;IvoVp$JOOz3%XibPXKlWQE{uGiMeJM zsY9xszm^hj^MkTLC;|M+WwEqRORGvL4~@-z!sj9%IMJF!SICcA@{a_v-+vAEK(4z- zrBNb;KmAwobwlIZSA!~AMOM_cBBA%iafoFobg$4J%JGHEaXwIO;~`WYB=UB*78&5iv%wd@6!p1}A6O zOM1`a@@`i}p9Te+)N6t(A+qD%717s;vdP&Kp9s+Tau!|>9a(8YG*tmy3$}c}5!wGD zVlJTlE}@Y4#zi4t|Y>qsc*-Fc#o!5Ay zu#GxIN~s86Fs~{;VoqiFtBFo8XS)@Ubl(#&>0cpspf*=j7jZ8;feaQtkJq>Ci)AjP zV5ap*GWl!Z)#-C=w30FMDexb!|FJ@>ci=Iv#0ft)o-i5+eLjVnx+D}C1m>q>_Sd95 zxmqZ_*ihdSo1y=WRO^mgOuGIdUafyG8o0yq1X&d>dyIN!cSO097tbb~l1Vw$`MY-v zO#^#+T9`h1qsPnt2r*r1Mm{~V>9E{}jG_~KhQ7S*p^!RYZE*R?l4gDf$}u+XYHj;0}w=Io=ifu619 zXA_&;l*tjY&RDNU#d@V4gO)GLQfkrC{#G$gypKBQ{0ycucspiFn$Yqg0vU7mrDC!I zXJ~1t`^C1s`FzjK;PZ2<{15GtZ&aS1c-7kk@+)^=w!l}m9v24kXXKE%kIz)di!^6n z>6hCgx8-^iI8 zFZi9ps4vHt9Xeo-9rZhe@Z+jvalVO z!sJ1MK)$U(MW$gz7gd4B-KD;nNxOR+t9pU2UjUsQe zN5aA!Z~YP2S934`MV8YuJ)i?(=GKcR;5KK!82sZU@S>+yI?bASp-2SRAPouT22c(^ zDmXYfWZ7mS?EJM~h=nnpu-%YTHl#^YJLhO@^GowM@ijM7szQv6PvmvZHIyg%O zVuds4rignBEoTS}SWg07v@JeZh7GBDQR%FpVdX;K+*?vCz8=Iis80q!e~XrfI9M=l z%{DxCYZFpALGM>I-B^~Kj8sPi^pfvZv~*pu^u^7F|6z4ol0qMapSP{}rz>S=GQ5zQ zU#eZKOfPcA^Bj%m`StAsfNesX4R!4<1bVLR~_cC<*;g?2zg5f8pAFLamqR9I)&gq+N)=1*e5&>)!NV53s zuvyF3i_7F~(3h9~=74hpgWMqp%(}H{bJj;02K(TjSHE6v`v_ye4Iikc*U}sGq=lg0 z4-qCB7CQPiMNe5x%hdl4RygaC8FL&-^VU@~J4}&VcO^_Vm7B0%wV2E@ z32zQcMwlC}RO*pVI>vx5M=nsi<71>}+8=1>T9fVO+3%LYU0gyvTDV)2Z5s$d&T$l8 z>{Wz)TjoOl%=ffPfzvKH z+dbk18I=8{<0;H$G8P%Y4Od!LkVn@l^9l=70X_3`e8t=*K}+-=oim^#7xM1+TO; zz3S2HnZ=votfeo!V&b<*V_u#}9xxwo@4fK3A)uzP0T071yG@-N1i;wnmfZ3|mdLMl zDAFg#r*#Oa20Z|+;Ji}hN5zF^m<=qN_8L8kcK%-noqT)enY>N^z5Wyn{KphPSJMzu Iso@a*KZ!k4q5uE@ diff --git a/tests/unit/assets/shared/images/arrows.xml b/tests/unit/assets/shared/images/arrows.xml deleted file mode 100644 index 96a73a38..00000000 --- a/tests/unit/assets/shared/images/arrows.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - From a243b167b2b1a76c70a7b68296d7e27f4410cff4 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 9 May 2024 22:37:01 -0400 Subject: [PATCH 004/131] Fix up more credits --- source/funkin/play/components/HealthIcon.hx | 2 +- source/funkin/ui/debug/charting/ChartEditorState.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/play/components/HealthIcon.hx b/source/funkin/play/components/HealthIcon.hx index 957daa43..2d7099e8 100644 --- a/source/funkin/play/components/HealthIcon.hx +++ b/source/funkin/play/components/HealthIcon.hx @@ -24,7 +24,7 @@ import funkin.util.MathUtil; * - i.e. `PlayState.instance.iconP1.playAnimation("losing")` * - Scripts can also utilize all functionality that a normal FlxSprite would have access to, such as adding supplimental animations. * - i.e. `PlayState.instance.iconP1.animation.addByPrefix("jumpscare", "jumpscare", 24, false);` - * @author MasterEric + * @author EliteMasterEric */ @:nullSafety class HealthIcon extends FunkinSprite diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index b75cd8bf..a313981f 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -137,7 +137,7 @@ using Lambda; * * Some functionality is split into handler classes to help maintain my sanity. * - * @author MasterEric + * @author EliteMasterEric */ // @:nullSafety From 5d5cf740204ac0b57712483a5e2a9fb0491b6eba Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 9 May 2024 22:37:21 -0400 Subject: [PATCH 005/131] Reimplement rank-based results animations. --- README.md | 2 +- assets | 2 +- source/funkin/play/ResultState.hx | 322 +++++++++++++++++++++--------- source/funkin/util/Constants.hx | 11 + 4 files changed, 240 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 39c098af..5728a6cb 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Please check out our [Contributor's guide](./CONTRIBUTORS.md) on how you can act ## Programming - [ninjamuffin99](https://twitter.com/ninja_muffin99) - Lead Programmer -- [MasterEric](https://twitter.com/EliteMasterEric) - Programmer +- [EliteMasterEric](https://twitter.com/EliteMasterEric) - Programmer - [MtH](https://twitter.com/emmnyaa) - Charting and Additional Programming - [GeoKureli](https://twitter.com/Geokureli/) - Additional Programming - Our contributors on GitHub diff --git a/assets b/assets index fe52d20d..6115eb68 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit fe52d20de7025d90cadb429dbdedf6d986727088 +Subproject commit 6115eb6837e97b8b3ad82f3ccd2a49a4383ed35b diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 56dd1e80..7f8bdd77 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -26,6 +26,7 @@ import funkin.play.components.TallyCounter; /** * The state for the results screen after a song or week is finished. */ +@:nullSafety class ResultState extends MusicBeatSubState { final params:ResultsStateParams; @@ -42,91 +43,45 @@ class ResultState extends MusicBeatSubState super(); this.params = params; + + resultsVariation = calculateVariation(params); + + var fontLetters:String = "AaBbCcDdEeFfGgHhiIJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz:1234567890"; + songName = new FlxBitmapText(FlxBitmapFont.fromMonospace(Paths.image("resultScreen/tardlingSpritesheet"), fontLetters, FlxPoint.get(49, 62))); + songName.text = params.title; + songName.letterSpacing = -15; + songName.angle = -4.4; + songName.zIndex = 1000; + + difficulty = new FlxSprite(555); + difficulty.zIndex = 1000; } override function create():Void { - /* - 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', + FunkinSound.playMusic(resultsVariation.getMusicPath(), { startingVolume: 1.0, overrideExisting: true, restartTrack: true, - loop: resultsVariation != SHIT + loop: resultsVariation.shouldMusicLoop() }); // Reset the camera zoom on the results screen. FlxG.camera.zoom = 1.0; - // TEMP-ish, just used to sorta "cache" the 3000x3000 image! - var cacheBullShit:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/soundSystem")); - add(cacheBullShit); - - 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(); + bg.zIndex = 10; add(bg); var bgFlash:FlxSprite = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFEB69, 0xFFFFE66A], 90); bgFlash.scrollFactor.set(); bgFlash.visible = false; + bg.zIndex = 20; add(bgFlash); - // var bfGfExcellent:FlxAtlasSprite = new FlxAtlasSprite(380, -170, Paths.animateAtlas("resultScreen/resultsBoyfriendExcellent", "shared")); - // bfGfExcellent.visible = false; - // add(bfGfExcellent); - // - // var bfPerfect:FlxAtlasSprite = new FlxAtlasSprite(370, -180, Paths.animateAtlas("resultScreen/resultsBoyfriendPerfect", "shared")); - // bfPerfect.visible = false; - // add(bfPerfect); - // - // var bfSHIT:FlxAtlasSprite = new FlxAtlasSprite(0, 20, Paths.animateAtlas("resultScreen/resultsBoyfriendSHIT", "shared")); - // bfSHIT.visible = false; - // add(bfSHIT); - // - // bfGfExcellent.anim.onComplete = () -> { - // bfGfExcellent.anim.curFrame = 28; - // bfGfExcellent.anim.play(); // unpauses this anim, since it's on PlayOnce! - // }; - // - // bfPerfect.anim.onComplete = () -> { - // bfPerfect.anim.curFrame = 136; - // bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! - // }; - // - // bfSHIT.anim.onComplete = () -> { - // bfSHIT.anim.curFrame = 150; - // bfSHIT.anim.play(); // unpauses this anim, since it's on PlayOnce! - // }; - - var gf:FlxSprite = FunkinSprite.createSparrow(625, 325, 'resultScreen/resultGirlfriendGOOD'); - gf.animation.addByPrefix("clap", "Girlfriend Good Anim", 24, false); - gf.visible = false; - gf.animation.finishCallback = _ -> { - gf.animation.play('clap', true, false, 9); - }; - add(gf); - - var boyfriend:FlxSprite = FunkinSprite.createSparrow(640, -200, 'resultScreen/resultBoyfriendGOOD'); - boyfriend.animation.addByPrefix("fall", "Boyfriend Good Anim0", 24, false); - boyfriend.visible = false; - boyfriend.animation.finishCallback = function(_) { - boyfriend.animation.play('fall', true, false, 14); - }; - - add(boyfriend); - + // The sound system which falls into place behind the score text. Plays every time! var soundSystem:FlxSprite = FunkinSprite.createSparrow(-15, -180, 'resultScreen/soundSystem'); soundSystem.animation.addByPrefix("idle", "sound system", 24, false); soundSystem.visible = false; @@ -134,9 +89,66 @@ class ResultState extends MusicBeatSubState soundSystem.animation.play("idle"); soundSystem.visible = true; }); + soundSystem.zIndex = 1100; add(soundSystem); - difficulty = new FlxSprite(555); + var bfPerfect:Null = null; + var bfExcellent:Null = null; + var bfGood:Null = null; + var gfGood:Null = null; + var bfShit:Null = null; + + switch (resultsVariation) + { + case PERFECT | PERFECT_GOLD | PERFECT_PLATINUM: + bfPerfect = new FlxAtlasSprite(370, -180, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT", "shared")); + bfPerfect.visible = false; + bfPerfect.zIndex = 500; + add(bfPerfect); + + bfPerfect.anim.onComplete = () -> { + bfPerfect.anim.curFrame = 136; + bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! + }; + + case EXCELLENT: + bfExcellent = new FlxAtlasSprite(380, -170, Paths.animateAtlas("resultScreen/results-bf/resultsEXCELLENT", "shared")); + bfExcellent.visible = false; + bfExcellent.zIndex = 500; + add(bfExcellent); + + bfExcellent.onAnimationFinish.add((animName) -> { + bfExcellent.playAnimation('Loop Start'); + }); + + case GOOD | GREAT: + gfGood = FunkinSprite.createSparrow(625, 325, 'resultScreen/results-bf/resultsGOOD/resultGirlfriendGOOD'); + gfGood.animation.addByPrefix("clap", "Girlfriend Good Anim", 24, false); + gfGood.visible = false; + gfGood.zIndex = 500; + gfGood.animation.finishCallback = _ -> { + gfGood.animation.play('clap', true, false, 9); + }; + add(gfGood); + + bfGood = FunkinSprite.createSparrow(640, -200, 'resultScreen/results-bf/resultsGOOD/resultBoyfriendGOOD'); + bfGood.animation.addByPrefix("fall", "Boyfriend Good Anim0", 24, false); + bfGood.visible = false; + bfGood.zIndex = 501; + bfGood.animation.finishCallback = function(_) { + bfGood.animation.play('fall', true, false, 14); + }; + add(bfGood); + + case SHIT: + bfShit = new FlxAtlasSprite(0, 20, Paths.animateAtlas("resultScreen/results-bf/resultsSHIT", "shared")); + bfShit.visible = false; + bfShit.zIndex = 500; + add(bfShit); + bfShit.onAnimationFinish.add((animName) -> { + bfShit.playAnimation('Loop Start'); + }); + } var diffSpr:String = switch (PlayState.instance.currentDifficulty) { @@ -157,11 +169,6 @@ class ResultState extends MusicBeatSubState difficulty.loadGraphic(Paths.image("resultScreen/" + diffSpr)); add(difficulty); - var fontLetters:String = "AaBbCcDdEeFfGgHhiIJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz:1234567890"; - songName = new FlxBitmapText(FlxBitmapFont.fromMonospace(Paths.image("resultScreen/tardlingSpritesheet"), fontLetters, FlxPoint.get(49, 62))); - songName.text = params.title; - songName.letterSpacing = -15; - songName.angle = -4.4; add(songName); var angleRad = songName.angle * Math.PI / 180; @@ -179,21 +186,25 @@ class ResultState extends MusicBeatSubState var blackTopBar:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/topBarBlack")); blackTopBar.y = -blackTopBar.height; FlxTween.tween(blackTopBar, {y: 0}, 0.4, {ease: FlxEase.quartOut, startDelay: 0.5}); + blackTopBar.zIndex = 1010; add(blackTopBar); var resultsAnim:FunkinSprite = FunkinSprite.createSparrow(-200, -10, "resultScreen/results"); resultsAnim.animation.addByPrefix("result", "results instance 1", 24, false); resultsAnim.animation.play("result"); + resultsAnim.zIndex = 1200; add(resultsAnim); var ratingsPopin:FunkinSprite = FunkinSprite.createSparrow(-150, 120, "resultScreen/ratingsPopin"); ratingsPopin.animation.addByPrefix("idle", "Categories", 24, false); ratingsPopin.visible = false; + ratingsPopin.zIndex = 1200; add(ratingsPopin); var scorePopin:FunkinSprite = FunkinSprite.createSparrow(-180, 520, "resultScreen/scorePopin"); scorePopin.animation.addByPrefix("score", "tally score", 24, false); scorePopin.visible = false; + scorePopin.zIndex = 1200; add(scorePopin); var highscoreNew:FlxSprite = new FlxSprite(310, 570); @@ -202,11 +213,13 @@ class ResultState extends MusicBeatSubState highscoreNew.visible = false; highscoreNew.setGraphicSize(Std.int(highscoreNew.width * 0.8)); highscoreNew.updateHitbox(); + highscoreNew.zIndex = 1200; add(highscoreNew); var hStuf:Int = 50; var ratingGrp:FlxTypedGroup = new FlxTypedGroup(); + ratingGrp.zIndex = 1200; add(ratingGrp); /** @@ -238,6 +251,7 @@ class ResultState extends MusicBeatSubState var score:ResultScore = new ResultScore(35, 305, 10, params.scoreData.score); score.visible = false; + score.zIndex = 1200; add(score); for (ind => rating in ratingGrp.members) @@ -275,40 +289,72 @@ class ResultState extends MusicBeatSubState switch (resultsVariation) { - // case SHIT: - // bfSHIT.visible = true; - // bfSHIT.playAnimation(""); + case PERFECT | PERFECT_GOLD | PERFECT_PLATINUM: + if (bfPerfect == null) + { + trace("Could not build PERFECT animation!"); + } + else + { + bfPerfect.visible = true; + bfPerfect.playAnimation(''); + } - case NORMAL: - boyfriend.animation.play('fall'); - boyfriend.visible = true; + case EXCELLENT: + if (bfExcellent == null) + { + trace("Could not build EXCELLENT animation!"); + } + else + { + bfExcellent.visible = true; + bfExcellent.playAnimation('Intro'); + } - new FlxTimer().start((1 / 24) * 12, _ -> { - bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - new FlxTimer().start((1 / 24) * 2, _ -> - { - // bgFlash.alpha = 0.5; + case SHIT: + if (bfShit == null) + { + trace("Could not build SHIT animation!"); + } + else + { + bfShit.visible = true; + bfShit.playAnimation('Intro'); + } - // bgFlash.visible = false; - }); - }); + case GREAT | GOOD: + if (bfGood == null || gfGood == null) + { + trace("Could not build GOOD animation!"); + } + else + { + bfGood.animation.play('fall'); + bfGood.visible = true; - new FlxTimer().start((1 / 24) * 22, _ -> { - // plays about 22 frames (at 24fps timing) after bf spawns in - gf.animation.play('clap', true); - gf.visible = true; - }); - // case PERFECT: - // bfPerfect.visible = true; - // bfPerfect.playAnimation(""); + new FlxTimer().start((1 / 24) * 12, _ -> { + bgFlash.visible = true; + FlxTween.tween(bgFlash, {alpha: 0}, 0.4); + new FlxTimer().start((1 / 24) * 2, _ -> + { + // bgFlash.alpha = 0.5; - // bfGfExcellent.visible = true; - // bfGfExcellent.playAnimation(""); + // bgFlash.visible = false; + }); + }); + + new FlxTimer().start((1 / 24) * 22, _ -> { + // plays about 22 frames (at 24fps timing) after bf spawns in + gfGood.animation.play('clap', true); + gfGood.visible = true; + }); + } default: } }); + refresh(); + super.create(); } @@ -401,14 +447,100 @@ class ResultState extends MusicBeatSubState super.update(elapsed); } + + public static function calculateVariation(params:ResultsStateParams):ResultVariations + { + // Perfect (Platinum) is a Sick Full Clear + var isPerfectPlat = (params.scoreData.tallies.sick + params.scoreData.tallies.good) == params.scoreData.tallies.totalNotes + && params.scoreData.tallies.sick / params.scoreData.tallies.totalNotes >= Constants.RANK_PERFECT_PLAT_THRESHOLD; + if (isPerfectPlat) return ResultVariations.PERFECT_PLATINUM; + + // Perfect (Gold) is an 85% Sick Full Clear + var isPerfectGold = (params.scoreData.tallies.sick + params.scoreData.tallies.good) == params.scoreData.tallies.totalNotes + && params.scoreData.tallies.sick / params.scoreData.tallies.totalNotes >= Constants.RANK_PERFECT_GOLD_THRESHOLD; + if (isPerfectGold) return ResultVariations.PERFECT_GOLD; + + // Else, use the standard grades + + // Clear % (including bad and shit). 1.00 is a full clear but not a full combo + var clear = (params.scoreData.tallies.totalNotesHit) / params.scoreData.tallies.totalNotes; + + if (clear == Constants.RANK_PERFECT_THRESHOLD) + { + return ResultVariations.PERFECT; + } + else if (clear >= Constants.RANK_EXCELLENT_THRESHOLD) + { + return ResultVariations.EXCELLENT; + } + else if (clear >= Constants.RANK_GREAT_THRESHOLD) + { + return ResultVariations.GREAT; + } + else if (clear >= Constants.RANK_GOOD_THRESHOLD) + { + return ResultVariations.GOOD; + } + else + { + return ResultVariations.SHIT; + } + } } enum abstract ResultVariations(String) { + var PERFECT_PLATINUM; + var PERFECT_GOLD; var PERFECT; var EXCELLENT; - var NORMAL; + var GREAT; + var GOOD; var SHIT; + + public function getMusicPath():String + { + switch (abstract) + { + case PERFECT_PLATINUM: + return 'resultsPERFECT'; + case PERFECT_GOLD: + return 'resultsPERFECT'; + case PERFECT: + return 'resultsPERFECT'; + case EXCELLENT: + return 'resultsNORMAL'; + case GREAT: + return 'resultsNORMAL'; + case GOOD: + return 'resultsNORMAL'; + case SHIT: + return 'resultsSHIT'; + } + } + + public function shouldMusicLoop():Bool + { + switch (abstract) + { + case PERFECT_PLATINUM: + return true; + case PERFECT_GOLD: + return true; + case PERFECT: + return true; + case EXCELLENT: + return true; + case GREAT: + return true; + case GOOD: + return true; + case SHIT: + return false; + default: + return false; + } + } } typedef ResultsStateParams = diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index c50f1769..2f3b570b 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -455,6 +455,17 @@ class Constants public static final JUDGEMENT_BAD_COMBO_BREAK:Bool = true; public static final JUDGEMENT_SHIT_COMBO_BREAK:Bool = true; + // % Sick + public static final RANK_PERFECT_PLAT_THRESHOLD:Float = 1.0; // % Sick + public static final RANK_PERFECT_GOLD_THRESHOLD:Float = 0.85; // % Sick + + // % Hit + public static final RANK_PERFECT_THRESHOLD:Float = 1.00; + public static final RANK_EXCELLENT_THRESHOLD:Float = 0.90; + public static final RANK_GREAT_THRESHOLD:Float = 0.75; + public static final RANK_GOOD_THRESHOLD:Float = 0.60; + + // public static final RANK_SHIT_THRESHOLD:Float = 0.00; /** * FILE EXTENSIONS */ From 98cf37b642292fcd7eb8a5913db5c7e08a43b82a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 9 May 2024 22:38:01 -0400 Subject: [PATCH 006/131] Update assets to add music. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 6115eb68..7df2e552 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 6115eb6837e97b8b3ad82f3ccd2a49a4383ed35b +Subproject commit 7df2e552738f8f2278538513a7495cb96d5ed118 From 83c3ff478c27bdc096e7dfcea190753df97526b5 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 10 May 2024 22:09:09 -0400 Subject: [PATCH 007/131] Added Clear % tally to results. --- assets | 2 +- source/funkin/play/ResultState.hx | 381 +++++++++++++++++++++--------- 2 files changed, 266 insertions(+), 117 deletions(-) diff --git a/assets b/assets index 7df2e552..927578f4 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 7df2e552738f8f2278538513a7495cb96d5ed118 +Subproject commit 927578f482b23dc4511fd8203560d631442d91a8 diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 7f8bdd77..df3134b9 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -12,6 +12,8 @@ import funkin.ui.MusicBeatSubState; import flixel.math.FlxRect; import flixel.text.FlxBitmapText; import funkin.ui.freeplay.FreeplayScore; +import flixel.text.FlxText; +import flixel.util.FlxColor; import flixel.tweens.FlxEase; import funkin.ui.freeplay.FreeplayState; import flixel.tweens.FlxTween; @@ -31,12 +33,27 @@ class ResultState extends MusicBeatSubState { final params:ResultsStateParams; - var resultsVariation:ResultVariations; - var songName:FlxBitmapText; - var difficulty:FlxSprite; + final rank:ResultRank; + final songName:FlxBitmapText; + final difficulty:FlxSprite; - var maskShaderSongName:LeftMaskShader = new LeftMaskShader(); - var maskShaderDifficulty:LeftMaskShader = new LeftMaskShader(); + final maskShaderSongName:LeftMaskShader = new LeftMaskShader(); + final maskShaderDifficulty:LeftMaskShader = new LeftMaskShader(); + + final resultsAnim:FunkinSprite; + final ratingsPopin:FunkinSprite; + final scorePopin:FunkinSprite; + + final bgFlash:FlxSprite; + + final highscoreNew:FlxSprite; + final score:ResultScore; + + var bfPerfect:Null = null; + var bfExcellent:Null = null; + var bfGood:Null = null; + var gfGood:Null = null; + var bfShit:Null = null; public function new(params:ResultsStateParams) { @@ -44,7 +61,11 @@ class ResultState extends MusicBeatSubState this.params = params; - resultsVariation = calculateVariation(params); + rank = calculateRank(params); + // rank = SHIT; + + // We build a lot of this stuff in the constructor, then place it in create(). + // This prevents having to do `null` checks everywhere. var fontLetters:String = "AaBbCcDdEeFfGgHhiIJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz:1234567890"; songName = new FlxBitmapText(FlxBitmapFont.fromMonospace(Paths.image("resultScreen/tardlingSpritesheet"), fontLetters, FlxPoint.get(49, 62))); @@ -55,18 +76,22 @@ class ResultState extends MusicBeatSubState difficulty = new FlxSprite(555); difficulty.zIndex = 1000; + + bgFlash = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFEB69, 0xFFFFE66A], 90); + + resultsAnim = FunkinSprite.createSparrow(-200, -10, "resultScreen/results"); + + ratingsPopin = FunkinSprite.createSparrow(-150, 120, "resultScreen/ratingsPopin"); + + scorePopin = FunkinSprite.createSparrow(-180, 520, "resultScreen/scorePopin"); + + highscoreNew = new FlxSprite(310, 570); + + score = new ResultScore(35, 305, 10, params.scoreData.score); } override function create():Void { - FunkinSound.playMusic(resultsVariation.getMusicPath(), - { - startingVolume: 1.0, - overrideExisting: true, - restartTrack: true, - loop: resultsVariation.shouldMusicLoop() - }); - // Reset the camera zoom on the results screen. FlxG.camera.zoom = 1.0; @@ -75,10 +100,9 @@ class ResultState extends MusicBeatSubState bg.zIndex = 10; add(bg); - var bgFlash:FlxSprite = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFEB69, 0xFFFFE66A], 90); bgFlash.scrollFactor.set(); bgFlash.visible = false; - bg.zIndex = 20; + bgFlash.zIndex = 20; add(bgFlash); // The sound system which falls into place behind the score text. Plays every time! @@ -92,13 +116,7 @@ class ResultState extends MusicBeatSubState soundSystem.zIndex = 1100; add(soundSystem); - var bfPerfect:Null = null; - var bfExcellent:Null = null; - var bfGood:Null = null; - var gfGood:Null = null; - var bfShit:Null = null; - - switch (resultsVariation) + switch (rank) { case PERFECT | PERFECT_GOLD | PERFECT_PLATINUM: bfPerfect = new FlxAtlasSprite(370, -180, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT", "shared")); @@ -107,8 +125,11 @@ class ResultState extends MusicBeatSubState add(bfPerfect); bfPerfect.anim.onComplete = () -> { - bfPerfect.anim.curFrame = 136; - bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! + if (bfPerfect != null) + { + bfPerfect.anim.curFrame = 137; + bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! + } }; case EXCELLENT: @@ -118,7 +139,10 @@ class ResultState extends MusicBeatSubState add(bfExcellent); bfExcellent.onAnimationFinish.add((animName) -> { - bfExcellent.playAnimation('Loop Start'); + if (bfExcellent != null) + { + bfExcellent.playAnimation('Loop Start'); + } }); case GOOD | GREAT: @@ -127,7 +151,10 @@ class ResultState extends MusicBeatSubState gfGood.visible = false; gfGood.zIndex = 500; gfGood.animation.finishCallback = _ -> { - gfGood.animation.play('clap', true, false, 9); + if (gfGood != null) + { + gfGood.animation.play('clap', true, false, 9); + } }; add(gfGood); @@ -136,7 +163,10 @@ class ResultState extends MusicBeatSubState bfGood.visible = false; bfGood.zIndex = 501; bfGood.animation.finishCallback = function(_) { - bfGood.animation.play('fall', true, false, 14); + if (bfGood != null) + { + bfGood.animation.play('fall', true, false, 14); + } }; add(bfGood); @@ -146,7 +176,10 @@ class ResultState extends MusicBeatSubState bfShit.zIndex = 500; add(bfShit); bfShit.onAnimationFinish.add((animName) -> { - bfShit.playAnimation('Loop Start'); + if (bfShit != null) + { + bfShit.playAnimation('Loop Start'); + } }); } @@ -189,25 +222,21 @@ class ResultState extends MusicBeatSubState blackTopBar.zIndex = 1010; add(blackTopBar); - var resultsAnim:FunkinSprite = FunkinSprite.createSparrow(-200, -10, "resultScreen/results"); resultsAnim.animation.addByPrefix("result", "results instance 1", 24, false); resultsAnim.animation.play("result"); resultsAnim.zIndex = 1200; add(resultsAnim); - var ratingsPopin:FunkinSprite = FunkinSprite.createSparrow(-150, 120, "resultScreen/ratingsPopin"); ratingsPopin.animation.addByPrefix("idle", "Categories", 24, false); ratingsPopin.visible = false; ratingsPopin.zIndex = 1200; add(ratingsPopin); - var scorePopin:FunkinSprite = FunkinSprite.createSparrow(-180, 520, "resultScreen/scorePopin"); scorePopin.animation.addByPrefix("score", "tally score", 24, false); scorePopin.visible = false; scorePopin.zIndex = 1200; add(scorePopin); - var highscoreNew:FlxSprite = new FlxSprite(310, 570); highscoreNew.frames = Paths.getSparrowAtlas("resultScreen/highscoreNew"); highscoreNew.animation.addByPrefix("new", "NEW HIGHSCORE", 24); highscoreNew.visible = false; @@ -249,7 +278,6 @@ class ResultState extends MusicBeatSubState var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.scoreData.tallies.missed, 0xFFC68AE6); ratingGrp.add(tallyMissed); - var score:ResultScore = new ResultScore(35, 305, 10, params.scoreData.score); score.visible = false; score.zIndex = 1200; add(score); @@ -263,7 +291,68 @@ class ResultState extends MusicBeatSubState }); } - new FlxTimer().start(0.5, _ -> { + startRankTallySequence(); + + refresh(); + + super.create(); + } + + var rankTallyTimer:Null = null; + var clearPercentTarget:Int = 100; + var clearPercentLerp:Int = 0; + + function startRankTallySequence():Void + { + clearPercentTarget = Math.floor((params.scoreData.tallies.totalNotesHit) / params.scoreData.tallies.totalNotes * 100); + // clearPercentTarget = 97; + + var clearPercentText = new FlxText(FlxG.width / 2, FlxG.height / 2, 0, 'CLEAR: ${clearPercentLerp}%'); + clearPercentText.setFormat(Paths.font('vcr.ttf'), 64, FlxColor.BLACK, FlxTextAlign.RIGHT); + clearPercentText.zIndex = 1000; + add(clearPercentText); + + rankTallyTimer = new FlxTimer().start(1 / 24, _ -> { + // Tick up. + if (clearPercentLerp < clearPercentTarget) + { + clearPercentLerp++; + + clearPercentText.text = 'CLEAR: ${clearPercentLerp}%'; + FunkinSound.playOnce(Paths.sound('scrollMenu')); + } + + // Don't overshoot. + if (clearPercentLerp > clearPercentTarget) + { + clearPercentLerp = clearPercentTarget; + } + + if (clearPercentLerp == clearPercentTarget) + { + if (rankTallyTimer != null) + { + rankTallyTimer.destroy(); + rankTallyTimer = null; + } + + // Play confirm sound. + FunkinSound.playOnce(Paths.sound('confirmMenu')); + + new FlxTimer().start(1.0, _ -> { + remove(clearPercentText); + + afterRankTallySequence(); + }); + } + }, 0); // 0 = Loop until stopped + + if (ratingsPopin == null) + { + trace("Could not build ratingsPopin!"); + } + else + { ratingsPopin.animation.play("idle"); ratingsPopin.visible = true; @@ -286,76 +375,139 @@ class ResultState extends MusicBeatSubState highscoreNew.visible = false; } }; - - switch (resultsVariation) - { - case PERFECT | PERFECT_GOLD | PERFECT_PLATINUM: - if (bfPerfect == null) - { - trace("Could not build PERFECT animation!"); - } - else - { - bfPerfect.visible = true; - bfPerfect.playAnimation(''); - } - - case EXCELLENT: - if (bfExcellent == null) - { - trace("Could not build EXCELLENT animation!"); - } - else - { - bfExcellent.visible = true; - bfExcellent.playAnimation('Intro'); - } - - case SHIT: - if (bfShit == null) - { - trace("Could not build SHIT animation!"); - } - else - { - bfShit.visible = true; - bfShit.playAnimation('Intro'); - } - - case GREAT | GOOD: - if (bfGood == null || gfGood == null) - { - trace("Could not build GOOD animation!"); - } - else - { - bfGood.animation.play('fall'); - bfGood.visible = true; - - new FlxTimer().start((1 / 24) * 12, _ -> { - bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - new FlxTimer().start((1 / 24) * 2, _ -> - { - // bgFlash.alpha = 0.5; - - // bgFlash.visible = false; - }); - }); - - new FlxTimer().start((1 / 24) * 22, _ -> { - // plays about 22 frames (at 24fps timing) after bf spawns in - gfGood.animation.play('clap', true); - gfGood.visible = true; - }); - } - default: - } - }); + } refresh(); + } - super.create(); + function afterRankTallySequence():Void + { + FunkinSound.playMusic(rank.getMusicPath(), + { + startingVolume: 1.0, + overrideExisting: true, + restartTrack: true, + loop: rank.shouldMusicLoop() + }); + + FlxG.sound.music.onComplete = () -> { + if (rank == SHIT) + { + FunkinSound.playMusic('bluu', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: true, + loop: true + }); + FlxG.sound.music.fadeIn(10.0, 0.0, 1.0); + } + } + + switch (rank) + { + case PERFECT | PERFECT_GOLD | PERFECT_PLATINUM: + if (bfPerfect == null) + { + trace("Could not build PERFECT animation!"); + } + else + { + bfPerfect.visible = true; + bfPerfect.playAnimation(''); + + new FlxTimer().start((1 / 24) * 12, _ -> { + bgFlash.visible = true; + FlxTween.tween(bgFlash, {alpha: 0}, 0.4); + new FlxTimer().start((1 / 24) * 2, _ -> + { + // bgFlash.alpha = 0.5; + + // bgFlash.visible = false; + }); + }); + } + + case EXCELLENT: + if (bfExcellent == null) + { + trace("Could not build EXCELLENT animation!"); + } + else + { + bfExcellent.visible = true; + bfExcellent.playAnimation('Intro'); + + new FlxTimer().start((1 / 24) * 12, _ -> { + bgFlash.visible = true; + FlxTween.tween(bgFlash, {alpha: 0}, 0.4); + new FlxTimer().start((1 / 24) * 2, _ -> + { + // bgFlash.alpha = 0.5; + + // bgFlash.visible = false; + }); + }); + } + + case SHIT: + if (bfShit == null) + { + trace("Could not build SHIT animation!"); + } + else + { + bfShit.visible = true; + bfShit.playAnimation('Intro'); + + new FlxTimer().start((1 / 24) * 12, _ -> { + bgFlash.visible = true; + FlxTween.tween(bgFlash, {alpha: 0}, 0.4); + new FlxTimer().start((1 / 24) * 2, _ -> + { + // bgFlash.alpha = 0.5; + + // bgFlash.visible = false; + }); + }); + } + + case GREAT | GOOD: + if (bfGood == null) + { + trace("Could not build GOOD animation!"); + } + else + { + bfGood.animation.play('fall'); + bfGood.visible = true; + + new FlxTimer().start((1 / 24) * 12, _ -> { + bgFlash.visible = true; + FlxTween.tween(bgFlash, {alpha: 0}, 0.4); + new FlxTimer().start((1 / 24) * 2, _ -> + { + // bgFlash.alpha = 0.5; + + // bgFlash.visible = false; + }); + }); + + new FlxTimer().start((1 / 24) * 22, _ -> { + // plays about 22 frames (at 24fps timing) after bf spawns in + if (gfGood != null) + { + gfGood.animation.play('clap', true); + gfGood.visible = true; + } + else + { + trace("Could not build GOOD animation!"); + } + }); + } + default: + } } function timerThenSongName():Void @@ -391,11 +543,8 @@ class ResultState extends MusicBeatSubState { super.draw(); - if (songName != null) - { - songName.clipRect = FlxRect.get(Math.max(0, 540 - songName.x), 0, FlxG.width, songName.height); - // PROBABLY SHOULD FIX MEMORY FREE OR WHATEVER THE PUT() FUNCTION DOES !!!! FEELS LIKE IT STUTTERS!!! - } + songName.clipRect = FlxRect.get(Math.max(0, 540 - songName.x), 0, FlxG.width, songName.height); + // PROBABLY SHOULD FIX MEMORY FREE OR WHATEVER THE PUT() FUNCTION DOES !!!! FEELS LIKE IT STUTTERS!!! // if (songName != null && songName.frame != null) // maskShaderSongName.frameUV = songName.frame.uv; @@ -448,17 +597,17 @@ class ResultState extends MusicBeatSubState super.update(elapsed); } - public static function calculateVariation(params:ResultsStateParams):ResultVariations + public static function calculateRank(params:ResultsStateParams):ResultRank { // Perfect (Platinum) is a Sick Full Clear var isPerfectPlat = (params.scoreData.tallies.sick + params.scoreData.tallies.good) == params.scoreData.tallies.totalNotes && params.scoreData.tallies.sick / params.scoreData.tallies.totalNotes >= Constants.RANK_PERFECT_PLAT_THRESHOLD; - if (isPerfectPlat) return ResultVariations.PERFECT_PLATINUM; + if (isPerfectPlat) return ResultRank.PERFECT_PLATINUM; // Perfect (Gold) is an 85% Sick Full Clear var isPerfectGold = (params.scoreData.tallies.sick + params.scoreData.tallies.good) == params.scoreData.tallies.totalNotes && params.scoreData.tallies.sick / params.scoreData.tallies.totalNotes >= Constants.RANK_PERFECT_GOLD_THRESHOLD; - if (isPerfectGold) return ResultVariations.PERFECT_GOLD; + if (isPerfectGold) return ResultRank.PERFECT_GOLD; // Else, use the standard grades @@ -467,28 +616,28 @@ class ResultState extends MusicBeatSubState if (clear == Constants.RANK_PERFECT_THRESHOLD) { - return ResultVariations.PERFECT; + return ResultRank.PERFECT; } else if (clear >= Constants.RANK_EXCELLENT_THRESHOLD) { - return ResultVariations.EXCELLENT; + return ResultRank.EXCELLENT; } else if (clear >= Constants.RANK_GREAT_THRESHOLD) { - return ResultVariations.GREAT; + return ResultRank.GREAT; } else if (clear >= Constants.RANK_GOOD_THRESHOLD) { - return ResultVariations.GOOD; + return ResultRank.GOOD; } else { - return ResultVariations.SHIT; + return ResultRank.SHIT; } } } -enum abstract ResultVariations(String) +enum abstract ResultRank(String) { var PERFECT_PLATINUM; var PERFECT_GOLD; From 6c2d18c72c7350ccefc4d9b15577c6092d663bed Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sat, 11 May 2024 01:05:51 -0400 Subject: [PATCH 008/131] Resurrected difficulty stars, fixed flame animation, fixed Random showing an album. --- assets | 2 +- source/funkin/play/song/Song.hx | 21 ++++ source/funkin/ui/freeplay/AlbumRoll.hx | 44 ++++---- source/funkin/ui/freeplay/DifficultyStars.hx | 106 +++++++++++++++++++ source/funkin/ui/freeplay/FreeplayFlames.hx | 21 +++- source/funkin/ui/freeplay/FreeplayState.hx | 23 ++-- source/funkin/ui/freeplay/SongMenuItem.hx | 2 +- 7 files changed, 183 insertions(+), 36 deletions(-) create mode 100644 source/funkin/ui/freeplay/DifficultyStars.hx diff --git a/assets b/assets index 927578f4..fd112e29 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 927578f482b23dc4511fd8203560d631442d91a8 +Subproject commit fd112e293ee0f823ee98d5b8bd8a85e934f772f6 diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index e71ae321..23d8d219 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -399,6 +399,27 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry + { + if (charId == null) charId = Constants.DEFAULT_CHARACTER; + + if (variations.contains(charId)) + { + return [charId]; + } + else + { + // TODO: How to exclude character variations while keeping other custom variations? + return variations; + } + } + /** * List all the difficulties in this song. * diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx index 35facf13..50f4a432 100644 --- a/source/funkin/ui/freeplay/AlbumRoll.hx +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -38,7 +38,7 @@ class AlbumRoll extends FlxSpriteGroup var newAlbumArt:FlxAtlasSprite; - // var difficultyStars:DifficultyStars; + var difficultyStars:DifficultyStars; var _exitMovers:Null; var albumData:Album; @@ -65,9 +65,9 @@ class AlbumRoll extends FlxSpriteGroup add(newAlbumArt); - // difficultyStars = new DifficultyStars(140, 39); - // difficultyStars.stars.visible = false; - // add(difficultyStars); + difficultyStars = new DifficultyStars(140, 39); + difficultyStars.stars.visible = false; + add(difficultyStars); } function onAlbumFinish(animName:String):Void @@ -86,9 +86,14 @@ class AlbumRoll extends FlxSpriteGroup { if (albumId == null) { - // difficultyStars.stars.visible = false; + this.visible = false; + difficultyStars.stars.visible = false; return; } + else + { + this.visible = true; + } albumData = AlbumRegistry.instance.fetchEntry(albumId); @@ -144,10 +149,10 @@ class AlbumRoll extends FlxSpriteGroup newAlbumArt.visible = true; newAlbumArt.playAnimation(animNames.get('$albumId-active'), false, false, false); - // difficultyStars.stars.visible = false; + difficultyStars.stars.visible = false; new FlxTimer().start(0.75, function(_) { // showTitle(); - // showStars(); + showStars(); }); } @@ -156,16 +161,17 @@ class AlbumRoll extends FlxSpriteGroup newAlbumArt.playAnimation(animNames.get('$albumId-trans'), false, false, false); } - // public function setDifficultyStars(?difficulty:Int):Void - // { - // if (difficulty == null) return; - // difficultyStars.difficulty = difficulty; - // } - // /** - // * Make the album stars visible. - // */ - // public function showStars():Void - // { - // difficultyStars.stars.visible = false; // true; - // } + public function setDifficultyStars(?difficulty:Int):Void + { + if (difficulty == null) return; + difficultyStars.difficulty = difficulty; + } + + /** + * Make the album stars visible. + */ + public function showStars():Void + { + difficultyStars.stars.visible = true; // true; + } } diff --git a/source/funkin/ui/freeplay/DifficultyStars.hx b/source/funkin/ui/freeplay/DifficultyStars.hx new file mode 100644 index 00000000..51526bcb --- /dev/null +++ b/source/funkin/ui/freeplay/DifficultyStars.hx @@ -0,0 +1,106 @@ +package funkin.ui.freeplay; + +import flixel.group.FlxSpriteGroup; +import funkin.graphics.adobeanimate.FlxAtlasSprite; +import funkin.graphics.shaders.HSVShader; + +class DifficultyStars extends FlxSpriteGroup +{ + /** + * Internal handler var for difficulty... ranges from 0... to 15 + * 0 is 1 star... 15 is 0 stars! + */ + var curDifficulty(default, set):Int = 0; + + /** + * Range between 0 and 15 + */ + public var difficulty(default, set):Int = 1; + + public var stars:FlxAtlasSprite; + + var flames:FreeplayFlames; + + var hsvShader:HSVShader; + + public function new(x:Float, y:Float) + { + super(x, y); + + hsvShader = new HSVShader(); + + flames = new FreeplayFlames(0, 0); + add(flames); + + stars = new FlxAtlasSprite(0, 0, Paths.animateAtlas("freeplay/freeplayStars")); + stars.anim.play("diff stars"); + add(stars); + + stars.shader = hsvShader; + + for (memb in flames.members) + memb.shader = hsvShader; + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // "loops" the current animation + // for clarity, the animation file looks like + // frame : stars + // 0-99: 1 star + // 100-199: 2 stars + // ...... + // 1300-1499: 15 stars + // 1500 : 0 stars + if (curDifficulty < 15 && stars.anim.curFrame >= (curDifficulty + 1) * 100) + { + stars.anim.play("diff stars", true, false, curDifficulty * 100); + } + } + + function set_difficulty(value:Int):Int + { + difficulty = value; + + if (difficulty <= 0) + { + difficulty = 0; + curDifficulty = 15; + } + else if (difficulty <= 15) + { + difficulty = value; + curDifficulty = difficulty - 1; + } + else + { + difficulty = 15; + curDifficulty = difficulty - 1; + } + + if (difficulty > 10) flames.flameCount = difficulty - 10; + else + flames.flameCount = 0; + + return difficulty; + } + + function set_curDifficulty(value:Int):Int + { + curDifficulty = value; + if (curDifficulty == 15) + { + stars.anim.play("diff stars", true, false, 1500); + stars.anim.pause(); + } + else + { + stars.anim.curFrame = Std.int(curDifficulty * 100); + stars.anim.play("diff stars", true, false, curDifficulty * 100); + } + + return curDifficulty; + } +} diff --git a/source/funkin/ui/freeplay/FreeplayFlames.hx b/source/funkin/ui/freeplay/FreeplayFlames.hx index c20d8589..f6b6f5c3 100644 --- a/source/funkin/ui/freeplay/FreeplayFlames.hx +++ b/source/funkin/ui/freeplay/FreeplayFlames.hx @@ -50,8 +50,19 @@ class FreeplayFlames extends FlxSpriteGroup } } + var timers:Array = []; + function set_flameCount(value:Int):Int { + // Stop all existing timers. + // This fixes a bug where quickly switching difficulties would show flames. + for (timer in timers) + { + timer.active = false; + timer.destroy(); + timers.remove(timer); + } + this.flameCount = value; var visibleCount:Int = 0; for (i in 0...5) @@ -62,10 +73,18 @@ class FreeplayFlames extends FlxSpriteGroup { if (!flame.visible) { - new FlxTimer().start(flameTimer * visibleCount, function(_) { + var nextTimer:FlxTimer = new FlxTimer().start(flameTimer * visibleCount, function(currentTimer:FlxTimer) { + if (i >= this.flameCount) + { + trace('EARLY EXIT'); + return; + } + timers.remove(currentTimer); flame.animation.play("flame", true); flame.visible = true; }); + timers.push(nextTimer); + visibleCount++; } } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 7b754384..23906828 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -120,8 +120,6 @@ class FreeplayState extends MusicBeatSubState var curCapsule:SongMenuItem; var curPlaying:Bool = false; - var displayedVariations:Array; - var dj:DJBoyfriend; var ostName:FlxText; @@ -184,10 +182,6 @@ class FreeplayState extends MusicBeatSubState // Add a null entry that represents the RANDOM option songs.push(null); - // TODO: This makes custom variations disappear from Freeplay. Figure out a better solution later. - // Default character (BF) shows default and Erect variations. Pico shows only Pico variations. - displayedVariations = (currentCharacter == 'bf') ? [Constants.DEFAULT_VARIATION, 'erect'] : [currentCharacter]; - // programmatically adds the songs via LevelRegistry and SongRegistry for (levelId in LevelRegistry.instance.listSortedLevelIds()) { @@ -195,7 +189,8 @@ class FreeplayState extends MusicBeatSubState { var song:Song = SongRegistry.instance.fetchEntry(songId); - // Only display songs which actually have available charts for the current character. + // Only display songs which actually have available difficulties for the current character. + var displayedVariations = song.getVariationsByCharId(currentCharacter); var availableDifficultiesForSong:Array = song.listDifficulties(displayedVariations, false); if (availableDifficultiesForSong.length == 0) continue; @@ -488,10 +483,6 @@ class FreeplayState extends MusicBeatSubState albumRoll.playIntro(); - new FlxTimer().start(0.75, function(_) { - // albumRoll.showTitle(); - }); - FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut}); diffSelLeft.visible = true; @@ -1072,6 +1063,9 @@ class FreeplayState extends MusicBeatSubState albumRoll.albumId = newAlbumId; albumRoll.skipIntro(); } + + // Set difficulty star count. + albumRoll.setDifficultyStars(daSong?.difficultyRating); } // Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String) @@ -1383,11 +1377,12 @@ class FreeplaySongData public var songName(default, null):String = ''; public var songCharacter(default, null):String = ''; - public var songRating(default, null):Int = 0; + public var difficultyRating(default, null):Int = 0; public var albumId(default, null):Null = null; public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY; - public var displayedVariations(default, null):Array = [Constants.DEFAULT_VARIATION]; + + var displayedVariations:Array = [Constants.DEFAULT_VARIATION]; function set_currentDifficulty(value:String):String { @@ -1417,7 +1412,7 @@ class FreeplaySongData if (songDifficulty == null) return; this.songName = songDifficulty.songName; this.songCharacter = songDifficulty.characters.opponent; - this.songRating = songDifficulty.difficultyRating; + this.difficultyRating = songDifficulty.difficultyRating; if (songDifficulty.album == null) { FlxG.log.warn('No album for: ${songDifficulty.songName}'); diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index f6d85e56..cf9b5248 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -168,7 +168,7 @@ class SongMenuItem extends FlxSpriteGroup songText.text = songData?.songName ?? 'Random'; // Update capsule character. if (songData?.songCharacter != null) setCharacter(songData.songCharacter); - updateDifficultyRating(songData?.songRating ?? 0); + updateDifficultyRating(songData?.difficultyRating ?? 0); // Update opacity, offsets, etc. updateSelected(); } From 0322a8388262ec8cda1eda8b69ceccd57652b6ef Mon Sep 17 00:00:00 2001 From: NotHyper-474 Date: Sun, 12 May 2024 23:16:12 -0300 Subject: [PATCH 009/131] Fix "Invalid argument '&'" error --- source/funkin/util/WindowUtil.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/util/WindowUtil.hx b/source/funkin/util/WindowUtil.hx index 763d8485..9930d688 100644 --- a/source/funkin/util/WindowUtil.hx +++ b/source/funkin/util/WindowUtil.hx @@ -24,7 +24,7 @@ class WindowUtil { #if CAN_OPEN_LINKS #if linux - Sys.command('/usr/bin/xdg-open', [targetUrl, '&']); + Sys.command('/usr/bin/xdg-open ' + targetUrl + ' &'); #else // This should work on Windows and HTML5. FlxG.openURL(targetUrl); From 24933f5bb9bc725b90b95db6a4b2782f0f71b9d5 Mon Sep 17 00:00:00 2001 From: Hyper_ Date: Mon, 13 May 2024 17:16:49 -0300 Subject: [PATCH 010/131] Replace concatenation with string interpolation --- source/funkin/util/WindowUtil.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/util/WindowUtil.hx b/source/funkin/util/WindowUtil.hx index 9930d688..07f6bc13 100644 --- a/source/funkin/util/WindowUtil.hx +++ b/source/funkin/util/WindowUtil.hx @@ -24,7 +24,7 @@ class WindowUtil { #if CAN_OPEN_LINKS #if linux - Sys.command('/usr/bin/xdg-open ' + targetUrl + ' &'); + Sys.command('/usr/bin/xdg-open $targetUrl &'); #else // This should work on Windows and HTML5. FlxG.openURL(targetUrl); From b6b93bb0c6686b3a89100c3b625dfd912380cda6 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 17 May 2024 20:26:34 -0400 Subject: [PATCH 011/131] Added clear percent, rank name, and background text. --- .vscode/launch.json | 9 +- .vscode/settings.json | 5 + assets | 2 +- source/funkin/InitState.hx | 24 ++ source/funkin/play/PlayState.hx | 18 +- source/funkin/play/ResultState.hx | 288 ++++++++++-------- .../play/components/ClearPercentCounter.hx | 96 ++++++ source/funkin/save/Save.hx | 8 +- .../funkin/save/migrator/SaveDataMigrator.hx | 15 +- source/funkin/ui/freeplay/FreeplayState.hx | 4 +- source/funkin/ui/mainmenu/MainMenuState.hx | 3 +- 11 files changed, 311 insertions(+), 161 deletions(-) create mode 100644 source/funkin/play/components/ClearPercentCounter.hx diff --git a/.vscode/launch.json b/.vscode/launch.json index 74f72b82..6dc1dc00 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,10 +3,17 @@ "configurations": [ { // Launch in native/CPP on Windows/OSX/Linux - "name": "Lime", + "name": "Lime Build+Debug", "type": "lime", "request": "launch" }, + { + // Launch in native/CPP on Windows/OSX/Linux + "name": "Lime Debug (No Build)", + "type": "lime", + "request": "launch", + "preLaunchTask": null + }, { // Launch in browser "name": "HTML5 Debug", diff --git a/.vscode/settings.json b/.vscode/settings.json index a8a67245..26fe0b04 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -155,6 +155,11 @@ "target": "hl", "args": ["-debug", "-DDIALOGUE"] }, + { + "label": "Windows / Debug (Results Screen Test)", + "target": "windows", + "args": ["-debug", "-DRESULTS"] + }, { "label": "Windows / Debug (Straight to Chart Editor)", "target": "windows", diff --git a/assets b/assets index fd112e29..ce7dabff 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit fd112e293ee0f823ee98d5b8bd8a85e934f772f6 +Subproject commit ce7dabffbebc154c9dda1f01e92dbef83e3405ab diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 00d34fad..6a52eaf5 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -214,6 +214,30 @@ class InitState extends FlxState #elseif STAGEBUILD // -DSTAGEBUILD FlxG.switchState(() -> new funkin.ui.debug.stage.StageBuilderState()); + #elseif RESULTS + // -DRESULTS + FlxG.switchState(() -> new funkin.play.ResultState( + { + storyMode: false, + title: "CUM SONG", + isNewHighscore: true, + scoreData: + { + score: 1_234_567, + tallies: + { + sick: 130, + good: 69, + bad: 69, + shit: 69, + missed: 69, + combo: 69, + maxCombo: 69, + totalNotesHit: 140, + totalNotes: 2000, + } + }, + })); #elseif ANIMDEBUG // -DANIMDEBUG FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState()); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 44ad819c..3e1d4cac 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2777,6 +2777,7 @@ class PlayState extends MusicBeatSubState deathCounter = 0; var isNewHighscore = false; + var prevScoreData:Null = Save.instance.getSongScore(currentSong.id, currentDifficulty); if (currentSong != null && currentSong.validScore) { @@ -2796,7 +2797,6 @@ class PlayState extends MusicBeatSubState totalNotesHit: Highscore.tallies.totalNotesHit, totalNotes: Highscore.tallies.totalNotes, }, - accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, }; // adds current song data into the tallies for the level (story levels) @@ -2833,7 +2833,7 @@ class PlayState extends MusicBeatSubState score: PlayStatePlaylist.campaignScore, tallies: { - // TODO: Sum up the values for the whole level! + // TODO: Sum up the values for the whole week! sick: 0, good: 0, bad: 0, @@ -2844,7 +2844,6 @@ class PlayState extends MusicBeatSubState totalNotesHit: 0, totalNotes: 0, }, - accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, }; if (Save.instance.isLevelHighScore(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignDifficulty, data)) @@ -2930,11 +2929,11 @@ class PlayState extends MusicBeatSubState { if (rightGoddamnNow) { - moveToResultsScreen(isNewHighscore); + moveToResultsScreen(isNewHighscore, prevScoreData); } else { - zoomIntoResultsScreen(isNewHighscore); + zoomIntoResultsScreen(isNewHighscore, prevScoreData); } } } @@ -3008,7 +3007,7 @@ class PlayState extends MusicBeatSubState /** * Play the camera zoom animation and then move to the results screen once it's done. */ - function zoomIntoResultsScreen(isNewHighscore:Bool):Void + function zoomIntoResultsScreen(isNewHighscore:Bool, ?prevScoreData:SaveScoreData):Void { trace('WENT TO RESULTS SCREEN!'); @@ -3048,7 +3047,7 @@ class PlayState extends MusicBeatSubState FlxTween.tween(camHUD, {alpha: 0}, 0.6, { onComplete: function(_) { - moveToResultsScreen(isNewHighscore); + moveToResultsScreen(isNewHighscore, prevScoreData); } }); @@ -3081,7 +3080,7 @@ class PlayState extends MusicBeatSubState /** * Move to the results screen right goddamn now. */ - function moveToResultsScreen(isNewHighscore:Bool):Void + function moveToResultsScreen(isNewHighscore:Bool, ?prevScoreData:SaveScoreData):Void { persistentUpdate = false; vocals.stop(); @@ -3093,6 +3092,8 @@ class PlayState extends MusicBeatSubState { storyMode: PlayStatePlaylist.isStoryMode, title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), + prevScoreData: prevScoreData, + difficultyId: currentDifficulty, scoreData: { score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : songScore, @@ -3108,7 +3109,6 @@ class PlayState extends MusicBeatSubState totalNotesHit: talliesToUse.totalNotesHit, totalNotes: talliesToUse.totalNotes, }, - accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, }, isNewHighscore: isNewHighscore }); diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index df3134b9..d038b778 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -24,6 +24,7 @@ import funkin.save.Save; import funkin.save.Save.SaveScoreData; import funkin.graphics.shaders.LeftMaskShader; import funkin.play.components.TallyCounter; +import funkin.play.components.ClearPercentCounter; /** * The state for the results screen after a song or week is finished. @@ -109,7 +110,7 @@ class ResultState extends MusicBeatSubState var soundSystem:FlxSprite = FunkinSprite.createSparrow(-15, -180, 'resultScreen/soundSystem'); soundSystem.animation.addByPrefix("idle", "sound system", 24, false); soundSystem.visible = false; - new FlxTimer().start(0.4, _ -> { + new FlxTimer().start(0.3, _ -> { soundSystem.animation.play("idle"); soundSystem.visible = true; }); @@ -118,7 +119,7 @@ class ResultState extends MusicBeatSubState switch (rank) { - case PERFECT | PERFECT_GOLD | PERFECT_PLATINUM: + case PERFECT | PERFECT_GOLD: bfPerfect = new FlxAtlasSprite(370, -180, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT", "shared")); bfPerfect.visible = false; bfPerfect.zIndex = 500; @@ -183,22 +184,7 @@ class ResultState extends MusicBeatSubState }); } - var diffSpr:String = switch (PlayState.instance.currentDifficulty) - { - case 'easy': - 'difEasy'; - case 'normal': - 'difNormal'; - case 'hard': - 'difHard'; - case 'erect': - 'difErect'; - case 'nightmare': - 'difNightmare'; - case _: - 'difNormal'; - } - + var diffSpr:String = 'dif${params?.difficultyId ?? 'Normal'}'; difficulty.loadGraphic(Paths.image("resultScreen/" + diffSpr)); add(difficulty); @@ -208,7 +194,7 @@ class ResultState extends MusicBeatSubState speedOfTween.x = -1.0 * Math.cos(angleRad); speedOfTween.y = -1.0 * Math.sin(angleRad); - timerThenSongName(); + timerThenSongName(1.0); songName.shader = maskShaderSongName; difficulty.shader = maskShaderDifficulty; @@ -218,24 +204,40 @@ class ResultState extends MusicBeatSubState var blackTopBar:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/topBarBlack")); blackTopBar.y = -blackTopBar.height; - FlxTween.tween(blackTopBar, {y: 0}, 0.4, {ease: FlxEase.quartOut, startDelay: 0.5}); + FlxTween.tween(blackTopBar, {y: 0}, 0.4, {ease: FlxEase.quartOut}); blackTopBar.zIndex = 1010; add(blackTopBar); resultsAnim.animation.addByPrefix("result", "results instance 1", 24, false); - resultsAnim.animation.play("result"); + resultsAnim.visible = false; resultsAnim.zIndex = 1200; add(resultsAnim); + new FlxTimer().start(0.3, _ -> { + resultsAnim.visible = true; + resultsAnim.animation.play("result"); + }); ratingsPopin.animation.addByPrefix("idle", "Categories", 24, false); ratingsPopin.visible = false; ratingsPopin.zIndex = 1200; add(ratingsPopin); + new FlxTimer().start(1.0, _ -> { + ratingsPopin.visible = true; + ratingsPopin.animation.play("idle"); + }); scorePopin.animation.addByPrefix("score", "tally score", 24, false); scorePopin.visible = false; scorePopin.zIndex = 1200; add(scorePopin); + new FlxTimer().start(1.0, _ -> { + scorePopin.visible = true; + scorePopin.animation.play("score"); + scorePopin.animation.finishCallback = anim -> { + score.visible = true; + score.animateNumbers(); + }; + }); highscoreNew.frames = Paths.getSparrowAtlas("resultScreen/highscoreNew"); highscoreNew.animation.addByPrefix("new", "NEW HIGHSCORE", 24); @@ -285,13 +287,26 @@ class ResultState extends MusicBeatSubState for (ind => rating in ratingGrp.members) { rating.visible = false; - new FlxTimer().start((0.3 * ind) + 0.55, _ -> { + new FlxTimer().start((0.3 * ind) + 1.20, _ -> { rating.visible = true; FlxTween.tween(rating, {curNumber: rating.neededNumber}, 0.5, {ease: FlxEase.quartOut}); }); } - startRankTallySequence(); + ratingsPopin.animation.finishCallback = anim -> { + startRankTallySequence(); + + if (params.isNewHighscore ?? false) + { + highscoreNew.visible = true; + highscoreNew.animation.play("new"); + FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); + } + else + { + highscoreNew.visible = false; + } + }; refresh(); @@ -304,48 +319,43 @@ class ResultState extends MusicBeatSubState function startRankTallySequence():Void { - clearPercentTarget = Math.floor((params.scoreData.tallies.totalNotesHit) / params.scoreData.tallies.totalNotes * 100); - // clearPercentTarget = 97; + clearPercentTarget = Math.floor((params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100); + clearPercentTarget = 100; - var clearPercentText = new FlxText(FlxG.width / 2, FlxG.height / 2, 0, 'CLEAR: ${clearPercentLerp}%'); - clearPercentText.setFormat(Paths.font('vcr.ttf'), 64, FlxColor.BLACK, FlxTextAlign.RIGHT); - clearPercentText.zIndex = 1000; - add(clearPercentText); + clearPercentLerp = Std.int(Math.max(0, clearPercentTarget - 36)); - rankTallyTimer = new FlxTimer().start(1 / 24, _ -> { - // Tick up. - if (clearPercentLerp < clearPercentTarget) + var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter(FlxG.width / 2 + 300, FlxG.height / 2 - 100, clearPercentTarget); + clearPercentCounter.curNumber = clearPercentLerp; + FlxTween.tween(clearPercentCounter, {curNumber: clearPercentTarget}, 1.5, { - clearPercentLerp++; + ease: FlxEase.quartOut, + onUpdate: _ -> { + // Only play the tick sound if the number increased. + if (clearPercentLerp != clearPercentCounter.curNumber) + { + clearPercentLerp = clearPercentCounter.curNumber; + FunkinSound.playOnce(Paths.sound('scrollMenu')); + } + }, + onComplete: _ -> { + // Play confirm sound. + FunkinSound.playOnce(Paths.sound('confirmMenu')); - clearPercentText.text = 'CLEAR: ${clearPercentLerp}%'; - FunkinSound.playOnce(Paths.sound('scrollMenu')); - } + // Flash background. + bgFlash.visible = true; + FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - // Don't overshoot. - if (clearPercentLerp > clearPercentTarget) - { - clearPercentLerp = clearPercentTarget; - } + displayRankText(); - if (clearPercentLerp == clearPercentTarget) - { - if (rankTallyTimer != null) - { - rankTallyTimer.destroy(); - rankTallyTimer = null; + new FlxTimer().start(2.0, _ -> { + // remove(clearPercentCounter); + + afterRankTallySequence(); + }); } - - // Play confirm sound. - FunkinSound.playOnce(Paths.sound('confirmMenu')); - - new FlxTimer().start(1.0, _ -> { - remove(clearPercentText); - - afterRankTallySequence(); - }); - } - }, 0); // 0 = Loop until stopped + }); + clearPercentCounter.zIndex = 450; + add(clearPercentCounter); if (ratingsPopin == null) { @@ -353,18 +363,15 @@ class ResultState extends MusicBeatSubState } else { - ratingsPopin.animation.play("idle"); - ratingsPopin.visible = true; + // ratingsPopin.animation.play("idle"); + // ratingsPopin.visible = true; ratingsPopin.animation.finishCallback = anim -> { - scorePopin.animation.play("score"); - scorePopin.animation.finishCallback = anim -> { - score.visible = true; - score.animateNumbers(); - }; - scorePopin.visible = true; + // scorePopin.animation.play("score"); - if (params.isNewHighscore) + // scorePopin.visible = true; + + if (params.isNewHighscore ?? false) { highscoreNew.visible = true; highscoreNew.animation.play("new"); @@ -380,6 +387,23 @@ class ResultState extends MusicBeatSubState refresh(); } + function displayRankText():Void + { + var rankTextVert:FunkinSprite = FunkinSprite.create(FlxG.width - 64, 100, rank.getVerTextAsset()); + rankTextVert.zIndex = 2000; + add(rankTextVert); + + for (i in 0...10) + { + var rankTextBack:FunkinSprite = FunkinSprite.create(FlxG.width / 2 - 80, 50, rank.getHorTextAsset()); + rankTextBack.y += (rankTextBack.height * i / 2) + 10; + rankTextBack.zIndex = 100; + add(rankTextBack); + } + + refresh(); + } + function afterRankTallySequence():Void { FunkinSound.playMusic(rank.getMusicPath(), @@ -406,7 +430,7 @@ class ResultState extends MusicBeatSubState switch (rank) { - case PERFECT | PERFECT_GOLD | PERFECT_PLATINUM: + case PERFECT | PERFECT_GOLD: if (bfPerfect == null) { trace("Could not build PERFECT animation!"); @@ -415,17 +439,6 @@ class ResultState extends MusicBeatSubState { bfPerfect.visible = true; bfPerfect.playAnimation(''); - - new FlxTimer().start((1 / 24) * 12, _ -> { - bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - new FlxTimer().start((1 / 24) * 2, _ -> - { - // bgFlash.alpha = 0.5; - - // bgFlash.visible = false; - }); - }); } case EXCELLENT: @@ -437,17 +450,6 @@ class ResultState extends MusicBeatSubState { bfExcellent.visible = true; bfExcellent.playAnimation('Intro'); - - new FlxTimer().start((1 / 24) * 12, _ -> { - bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - new FlxTimer().start((1 / 24) * 2, _ -> - { - // bgFlash.alpha = 0.5; - - // bgFlash.visible = false; - }); - }); } case SHIT: @@ -459,17 +461,6 @@ class ResultState extends MusicBeatSubState { bfShit.visible = true; bfShit.playAnimation('Intro'); - - new FlxTimer().start((1 / 24) * 12, _ -> { - bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - new FlxTimer().start((1 / 24) * 2, _ -> - { - // bgFlash.alpha = 0.5; - - // bgFlash.visible = false; - }); - }); } case GREAT | GOOD: @@ -482,17 +473,6 @@ class ResultState extends MusicBeatSubState bfGood.animation.play('fall'); bfGood.visible = true; - new FlxTimer().start((1 / 24) * 12, _ -> { - bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - new FlxTimer().start((1 / 24) * 2, _ -> - { - // bgFlash.alpha = 0.5; - - // bgFlash.visible = false; - }); - }); - new FlxTimer().start((1 / 24) * 22, _ -> { // plays about 22 frames (at 24fps timing) after bf spawns in if (gfGood != null) @@ -510,7 +490,7 @@ class ResultState extends MusicBeatSubState } } - function timerThenSongName():Void + function timerThenSongName(timerLength:Float = 3.0):Void { movingSongStuff = false; @@ -526,7 +506,7 @@ class ResultState extends MusicBeatSubState FlxTween.tween(songName, {y: diffYTween - 35 - fuckedupnumber}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9}); songName.x = (difficulty.x + difficulty.width) + 20; - new FlxTimer().start(3, _ -> { + new FlxTimer().start(timerLength, _ -> { var tempSpeed = FlxPoint.get(speedOfTween.x, speedOfTween.y); speedOfTween.set(0, 0); @@ -600,33 +580,29 @@ class ResultState extends MusicBeatSubState public static function calculateRank(params:ResultsStateParams):ResultRank { // Perfect (Platinum) is a Sick Full Clear - var isPerfectPlat = (params.scoreData.tallies.sick + params.scoreData.tallies.good) == params.scoreData.tallies.totalNotes - && params.scoreData.tallies.sick / params.scoreData.tallies.totalNotes >= Constants.RANK_PERFECT_PLAT_THRESHOLD; - if (isPerfectPlat) return ResultRank.PERFECT_PLATINUM; - - // Perfect (Gold) is an 85% Sick Full Clear - var isPerfectGold = (params.scoreData.tallies.sick + params.scoreData.tallies.good) == params.scoreData.tallies.totalNotes - && params.scoreData.tallies.sick / params.scoreData.tallies.totalNotes >= Constants.RANK_PERFECT_GOLD_THRESHOLD; + var isPerfectGold = params.scoreData.tallies.sick == params.scoreData.tallies.totalNotes; if (isPerfectGold) return ResultRank.PERFECT_GOLD; // Else, use the standard grades + // Grade % (only good and sick), 1.00 is a full combo + var grade = (params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes; // Clear % (including bad and shit). 1.00 is a full clear but not a full combo var clear = (params.scoreData.tallies.totalNotesHit) / params.scoreData.tallies.totalNotes; - if (clear == Constants.RANK_PERFECT_THRESHOLD) + if (grade == Constants.RANK_PERFECT_THRESHOLD) { return ResultRank.PERFECT; } - else if (clear >= Constants.RANK_EXCELLENT_THRESHOLD) + else if (grade >= Constants.RANK_EXCELLENT_THRESHOLD) { return ResultRank.EXCELLENT; } - else if (clear >= Constants.RANK_GREAT_THRESHOLD) + else if (grade >= Constants.RANK_GREAT_THRESHOLD) { return ResultRank.GREAT; } - else if (clear >= Constants.RANK_GOOD_THRESHOLD) + else if (grade >= Constants.RANK_GOOD_THRESHOLD) { return ResultRank.GOOD; } @@ -639,7 +615,6 @@ class ResultState extends MusicBeatSubState enum abstract ResultRank(String) { - var PERFECT_PLATINUM; var PERFECT_GOLD; var PERFECT; var EXCELLENT; @@ -651,8 +626,6 @@ enum abstract ResultRank(String) { switch (abstract) { - case PERFECT_PLATINUM: - return 'resultsPERFECT'; case PERFECT_GOLD: return 'resultsPERFECT'; case PERFECT: @@ -665,6 +638,8 @@ enum abstract ResultRank(String) return 'resultsNORMAL'; case SHIT: return 'resultsSHIT'; + default: + return 'resultsNORMAL'; } } @@ -672,8 +647,6 @@ enum abstract ResultRank(String) { switch (abstract) { - case PERFECT_PLATINUM: - return true; case PERFECT_GOLD: return true; case PERFECT: @@ -690,6 +663,48 @@ enum abstract ResultRank(String) return false; } } + + public function getHorTextAsset() + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultScreen/rankText/rankScrollPERFECT'; + case PERFECT: + return 'resultScreen/rankText/rankScrollPERFECT'; + case EXCELLENT: + return 'resultScreen/rankText/rankScrollEXCELLENT'; + case GREAT: + return 'resultScreen/rankText/rankScrollGREAT'; + case GOOD: + return 'resultScreen/rankText/rankScrollGOOD'; + case SHIT: + return 'resultScreen/rankText/rankScrollLOSS'; + default: + return 'resultScreen/rankText/rankScrollGOOD'; + } + } + + public function getVerTextAsset() + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultScreen/rankText/rankTextPERFECT'; + case PERFECT: + return 'resultScreen/rankText/rankTextPERFECT'; + case EXCELLENT: + return 'resultScreen/rankText/rankTextEXCELLENT'; + case GREAT: + return 'resultScreen/rankText/rankTextGREAT'; + case GOOD: + return 'resultScreen/rankText/rankTextGOOD'; + case SHIT: + return 'resultScreen/rankText/rankTextLOSS'; + default: + return 'resultScreen/rankText/rankTextGOOD'; + } + } } typedef ResultsStateParams = @@ -707,10 +722,21 @@ typedef ResultsStateParams = /** * Whether the displayed score is a new highscore */ - var isNewHighscore:Bool; + var ?isNewHighscore:Bool; + + /** + * The difficulty ID of the song/week we just played. + * @default Normal + */ + var ?difficultyId:String; /** * The score, accuracy, and judgements. */ var scoreData:SaveScoreData; + + /** + * The previous score data, used for rank comparision. + */ + var ?prevScoreData:SaveScoreData; }; diff --git a/source/funkin/play/components/ClearPercentCounter.hx b/source/funkin/play/components/ClearPercentCounter.hx new file mode 100644 index 00000000..4c03ec3a --- /dev/null +++ b/source/funkin/play/components/ClearPercentCounter.hx @@ -0,0 +1,96 @@ +package funkin.play.components; + +import funkin.graphics.FunkinSprite; +import flixel.FlxSprite; +import flixel.group.FlxGroup.FlxTypedGroup; +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 to display the clear percent. + */ +class ClearPercentCounter extends FlxTypedSpriteGroup +{ + public var curNumber:Int = 0; + public var neededNumber:Int = 0; + + public function new(x:Float, y:Float, neededNumber:Int = 0) + { + super(x, y); + + this.neededNumber = neededNumber; + + var clearPercentText:FunkinSprite = FunkinSprite.create(0, 0, 'resultScreen/clearPercent/clearPercentText'); + add(clearPercentText); + + if (curNumber == neededNumber) drawNumbers(); + } + + var tmr:Float = 0; + + override function update(elapsed:Float) + { + super.update(elapsed); + + if (curNumber < neededNumber) drawNumbers(); + } + + function drawNumbers() + { + 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); + tempCombo = Math.floor(tempCombo / 10); + } + + if (seperatedScore.length == 0) seperatedScore.push(0); + + seperatedScore.reverse(); + + for (ind => num in seperatedScore) + { + var digitIndex = ind + 1; + if (digitIndex >= members.length) + { + var xPos = (digitIndex - 1) * (72 * this.scale.x); + var yPos = 72; + // Three digits = LRL so two different numbers aren't adjacent to each other. + var variant:Bool = (fullNumberDigits % 2 != 0) ? (digitIndex % 2 == 0) : (digitIndex % 2 == 1); + var numb:ClearPercentNumber = new ClearPercentNumber(xPos, yPos, num); + numb.scale.set(this.scale.x, this.scale.y); + add(numb); + } + else + { + members[digitIndex].animation.play(Std.string(num)); + } + } + } +} + +class ClearPercentNumber extends FlxSprite +{ + public function new(x:Float, y:Float, digit:Int, variant:Bool = false) + { + super(x, y); + + frames = Paths.getSparrowAtlas('resultScreen/clearPercent/clearPercentNumber${variant ? 'Right' : 'Left'}'); + + for (i in 0...10) + { + animation.addByPrefix('$i', 'number $i 0', 24, false); + } + + animation.play('$digit'); + updateHitbox(); + } +} diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index acbe59ed..08614e30 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -53,7 +53,8 @@ class Save public function new(?data:RawSaveData) { if (data == null) this.data = Save.getDefault(); - else this.data = data; + else + this.data = data; } public static function getDefault():RawSaveData @@ -809,11 +810,6 @@ typedef SaveScoreData = * The count of each judgement hit. */ var tallies:SaveScoreTallyData; - - /** - * The accuracy percentage. - */ - var accuracy:Float; } typedef SaveScoreTallyData = diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index 3ed59e72..9e308cb1 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -118,7 +118,7 @@ class SaveDataMigrator var scoreDataEasy:SaveScoreData = { score: inputSaveData.songScores.get('${levelId}-easy') ?? 0, - accuracy: inputSaveData.songCompletion.get('${levelId}-easy') ?? 0.0, + // accuracy: inputSaveData.songCompletion.get('${levelId}-easy') ?? 0.0, tallies: { sick: 0, @@ -137,7 +137,7 @@ class SaveDataMigrator var scoreDataNormal:SaveScoreData = { score: inputSaveData.songScores.get('${levelId}') ?? 0, - accuracy: inputSaveData.songCompletion.get('${levelId}') ?? 0.0, + // accuracy: inputSaveData.songCompletion.get('${levelId}') ?? 0.0, tallies: { sick: 0, @@ -156,7 +156,7 @@ class SaveDataMigrator var scoreDataHard:SaveScoreData = { score: inputSaveData.songScores.get('${levelId}-hard') ?? 0, - accuracy: inputSaveData.songCompletion.get('${levelId}-hard') ?? 0.0, + // accuracy: inputSaveData.songCompletion.get('${levelId}-hard') ?? 0.0, tallies: { sick: 0, @@ -178,7 +178,6 @@ class SaveDataMigrator var scoreDataEasy:SaveScoreData = { score: 0, - accuracy: 0, tallies: { sick: 0, @@ -196,14 +195,13 @@ class SaveDataMigrator for (songId in songIds) { scoreDataEasy.score = Std.int(Math.max(scoreDataEasy.score, inputSaveData.songScores.get('${songId}-easy') ?? 0)); - scoreDataEasy.accuracy = Math.max(scoreDataEasy.accuracy, inputSaveData.songCompletion.get('${songId}-easy') ?? 0.0); + // scoreDataEasy.accuracy = Math.max(scoreDataEasy.accuracy, inputSaveData.songCompletion.get('${songId}-easy') ?? 0.0); } result.setSongScore(songIds[0], 'easy', scoreDataEasy); var scoreDataNormal:SaveScoreData = { score: 0, - accuracy: 0, tallies: { sick: 0, @@ -221,14 +219,13 @@ class SaveDataMigrator for (songId in songIds) { scoreDataNormal.score = Std.int(Math.max(scoreDataNormal.score, inputSaveData.songScores.get('${songId}') ?? 0)); - scoreDataNormal.accuracy = Math.max(scoreDataNormal.accuracy, inputSaveData.songCompletion.get('${songId}') ?? 0.0); + // scoreDataNormal.accuracy = Math.max(scoreDataNormal.accuracy, inputSaveData.songCompletion.get('${songId}') ?? 0.0); } result.setSongScore(songIds[0], 'normal', scoreDataNormal); var scoreDataHard:SaveScoreData = { score: 0, - accuracy: 0, tallies: { sick: 0, @@ -246,7 +243,7 @@ class SaveDataMigrator for (songId in songIds) { scoreDataHard.score = Std.int(Math.max(scoreDataHard.score, inputSaveData.songScores.get('${songId}-hard') ?? 0)); - scoreDataHard.accuracy = Math.max(scoreDataHard.accuracy, inputSaveData.songCompletion.get('${songId}-hard') ?? 0.0); + // scoreDataHard.accuracy = Math.max(scoreDataHard.accuracy, inputSaveData.songCompletion.get('${songId}-hard') ?? 0.0); } result.setSongScore(songIds[0], 'hard', scoreDataHard); } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 23906828..dbf223dc 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -998,7 +998,7 @@ class FreeplayState extends MusicBeatSubState { var songScore:SaveScoreData = Save.instance.getSongScore(grpCapsules.members[curSelected].songData.songId, currentDifficulty); intendedScore = songScore?.score ?? 0; - intendedCompletion = songScore?.accuracy ?? 0.0; + intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick + songScore.tallies.good) / songScore.tallies.totalNotes); rememberedDifficulty = currentDifficulty; } else @@ -1196,7 +1196,7 @@ class FreeplayState extends MusicBeatSubState { var songScore:SaveScoreData = Save.instance.getSongScore(daSongCapsule.songData.songId, currentDifficulty); intendedScore = songScore?.score ?? 0; - intendedCompletion = songScore?.accuracy ?? 0.0; + intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick + songScore.tallies.good) / songScore.tallies.totalNotes); diffIdsCurrent = daSongCapsule.songData.songDifficulties; rememberedSongId = daSongCapsule.songData.songId; changeDiff(); diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index 466dbbb9..fcff41df 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -355,8 +355,7 @@ class MainMenuState extends MusicBeatState maxCombo: 0, totalNotesHit: 0, totalNotes: 0, - }, - accuracy: 0, + } }); } #end From bc1c15e91cdac75f7402840dbaf06811b8d44153 Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Sun, 19 May 2024 00:29:46 +0200 Subject: [PATCH 012/131] Add Remember Selection to MainMenuState --- source/funkin/ui/mainmenu/MainMenuState.hx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index 7a21a6e8..558a3483 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -42,6 +42,8 @@ class MainMenuState extends MusicBeatState var magenta:FlxSprite; var camFollow:FlxObject; + static var rememberedSelectedIndex:Int = 0; + override function create():Void { #if discord_rpc @@ -137,6 +139,8 @@ class MainMenuState extends MusicBeatState menuItem.scrollFactor.y = 0.4; } + menuItems.selectItem(rememberedSelectedIndex); + resetCamStuff(); subStateOpened.add(sub -> { @@ -285,6 +289,8 @@ class MainMenuState extends MusicBeatState function startExitState(state:NextState):Void { menuItems.enabled = false; // disable for exit + rememberedSelectedIndex = menuItems.selectedIndex; + var duration = 0.4; menuItems.forEach(function(item) { if (menuItems.selectedIndex != item.ID) From faf7a0643cd83bbf99ac99e302c6aaf2bcdebd30 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sun, 19 May 2024 01:47:36 -0400 Subject: [PATCH 013/131] Tinkered with ghost tapping some, leaving it off for now tho. --- source/funkin/play/PlayState.hx | 24 ++++++++++++++---------- source/funkin/play/notes/Strumline.hx | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 44ad819c..5b95c467 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2298,8 +2298,6 @@ class PlayState extends MusicBeatSubState var notesInRange:Array = playerStrumline.getNotesMayHit(); var holdNotesInRange:Array = playerStrumline.getHoldNotesHitOrMissed(); - // If there are notes in range, pressing a key will cause a ghost miss. - var notesByDirection:Array> = [[], [], [], []]; for (note in notesInRange) @@ -2321,17 +2319,27 @@ class PlayState extends MusicBeatSubState // Play the strumline animation. playerStrumline.playPress(input.noteDirection); + trace('PENALTY Score: ${songScore}'); } - else if (Constants.GHOST_TAPPING && (holdNotesInRange.length + notesInRange.length > 0) && notesInDirection.length == 0) + else if (Constants.GHOST_TAPPING && (!playerStrumline.mayGhostTap()) && notesInDirection.length == 0) { - // Pressed a wrong key with no notes nearby AND with notes in a different direction available. + // Pressed a wrong key with notes visible on-screen. // Perform a ghost miss (anti-spam). ghostNoteMiss(input.noteDirection, notesInRange.length > 0); // Play the strumline animation. playerStrumline.playPress(input.noteDirection); + trace('PENALTY Score: ${songScore}'); } - else if (notesInDirection.length > 0) + else if (notesInDirection.length == 0) + { + // Press a key with no penalty. + + // Play the strumline animation. + playerStrumline.playPress(input.noteDirection); + trace('NO PENALTY Score: ${songScore}'); + } + else { // Choose the first note, deprioritizing low priority notes. var targetNote:Null = notesInDirection.find((note) -> !note.lowPriority); @@ -2341,17 +2349,13 @@ class PlayState extends MusicBeatSubState // Judge and hit the note. trace('Hit note! ${targetNote.noteData}'); goodNoteHit(targetNote, input); + trace('Score: ${songScore}'); notesInDirection.remove(targetNote); // Play the strumline animation. playerStrumline.playConfirm(input.noteDirection); } - else - { - // Play the strumline animation. - playerStrumline.playPress(input.noteDirection); - } } while (inputReleaseQueue.length > 0) diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index 6a18f17d..220b6723 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -171,6 +171,20 @@ class Strumline extends FlxSpriteGroup updateNotes(); } + /** + * Returns `true` if no notes are in range of the strumline and the player can spam without penalty. + */ + public function mayGhostTap():Bool + { + // TODO: Refine this. Only querying "can be hit" is too tight but "is being rendered" is too loose. + // Also, if you just hit a note, there should be a (short) period where this is off so you can't spam. + + // If there are any notes on screen, we can't ghost tap. + return notes.members.filter(function(note:NoteSprite) { + return note != null && note.alive && !note.hasBeenHit; + }).length == 0; + } + /** * Return notes that are within `Constants.HIT_WINDOW` ms of the strumline. * @return An array of `NoteSprite` objects. From 228ac66cc2e9966c0eae1f4bc050477ff9cba93f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sun, 19 May 2024 01:48:51 -0400 Subject: [PATCH 014/131] Credit the song's charter in the pause menu. --- assets | 2 +- source/funkin/data/song/SongData.hx | 3 + source/funkin/data/song/SongRegistry.hx | 2 +- .../data/song/importer/FNFLegacyImporter.hx | 2 +- source/funkin/play/PauseSubState.hx | 89 +++++++++++++++++-- source/funkin/play/song/Song.hx | 15 ++++ .../ui/debug/charting/ChartEditorState.hx | 2 +- .../toolboxes/ChartEditorMetadataToolbox.hx | 16 ++++ source/funkin/util/Constants.hx | 5 ++ 9 files changed, 127 insertions(+), 9 deletions(-) diff --git a/assets b/assets index fd112e29..778e1670 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit fd112e293ee0f823ee98d5b8bd8a85e934f772f6 +Subproject commit 778e16705b30af85087f627594c22f4b5ba6141a diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index 26380947..bd25139a 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -30,6 +30,9 @@ class SongMetadata implements ICloneable @:default("Unknown") public var artist:String; + @:optional + public var charter:Null = null; + @:optional @:default(96) public var divisions:Null; // Optional field diff --git a/source/funkin/data/song/SongRegistry.hx b/source/funkin/data/song/SongRegistry.hx index 277dcd9e..a3305c4e 100644 --- a/source/funkin/data/song/SongRegistry.hx +++ b/source/funkin/data/song/SongRegistry.hx @@ -20,7 +20,7 @@ class SongRegistry extends BaseRegistry * Handle breaking changes by incrementing this value * and adding migration to the `migrateStageData()` function. */ - public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.2"; + public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.3"; public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.2.x"; diff --git a/source/funkin/data/song/importer/FNFLegacyImporter.hx b/source/funkin/data/song/importer/FNFLegacyImporter.hx index ab2abda8..fdfac7f7 100644 --- a/source/funkin/data/song/importer/FNFLegacyImporter.hx +++ b/source/funkin/data/song/importer/FNFLegacyImporter.hx @@ -36,7 +36,7 @@ class FNFLegacyImporter { trace('Migrating song metadata from FNF Legacy.'); - var songMetadata:SongMetadata = new SongMetadata('Import', 'Kawai Sprite', 'default'); + var songMetadata:SongMetadata = new SongMetadata('Import', Constants.DEFAULT_ARTIST, 'default'); var hadError:Bool = false; diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index fb9d9b4e..c345871a 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -101,6 +101,10 @@ class PauseSubState extends MusicBeatSubState */ static final MUSIC_FINAL_VOLUME:Float = 0.75; + static final CHARTER_FADE_DELAY:Float = 15.0; + + static final CHARTER_FADE_DURATION:Float = 0.75; + /** * Defines which pause music to use. */ @@ -163,6 +167,12 @@ class PauseSubState extends MusicBeatSubState */ var metadataDeaths:FlxText; + /** + * A text object which displays the current song's artist. + * Fades to the charter after a period before fading back. + */ + var metadataArtist:FlxText; + /** * The actual text objects for the menu entries. */ @@ -203,6 +213,8 @@ class PauseSubState extends MusicBeatSubState regenerateMenu(); transitionIn(); + + startCharterTimer(); } /** @@ -222,6 +234,8 @@ class PauseSubState extends MusicBeatSubState public override function destroy():Void { super.destroy(); + charterFadeTween.destroy(); + charterFadeTween = null; pauseMusic.stop(); } @@ -270,16 +284,25 @@ class PauseSubState extends MusicBeatSubState metadata.scrollFactor.set(0, 0); add(metadata); - var metadataSong:FlxText = new FlxText(20, 15, FlxG.width - 40, 'Song Name - Artist'); + var metadataSong:FlxText = new FlxText(20, 15, FlxG.width - 40, 'Song Name'); metadataSong.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT); if (PlayState.instance?.currentChart != null) { - metadataSong.text = '${PlayState.instance.currentChart.songName} - ${PlayState.instance.currentChart.songArtist}'; + metadataSong.text = '${PlayState.instance.currentChart.songName}'; } metadataSong.scrollFactor.set(0, 0); metadata.add(metadataSong); - var metadataDifficulty:FlxText = new FlxText(20, 15 + 32, FlxG.width - 40, 'Difficulty: '); + metadataArtist = new FlxText(20, metadataSong.y + 32, FlxG.width - 40, 'Artist: ${Constants.DEFAULT_ARTIST}'); + metadataArtist.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT); + if (PlayState.instance?.currentChart != null) + { + metadataArtist.text = 'Artist: ${PlayState.instance.currentChart.songArtist}'; + } + metadataArtist.scrollFactor.set(0, 0); + metadata.add(metadataArtist); + + var metadataDifficulty:FlxText = new FlxText(20, metadataArtist.y + 32, FlxG.width - 40, 'Difficulty: '); metadataDifficulty.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT); if (PlayState.instance?.currentDifficulty != null) { @@ -288,12 +311,12 @@ class PauseSubState extends MusicBeatSubState metadataDifficulty.scrollFactor.set(0, 0); metadata.add(metadataDifficulty); - metadataDeaths = new FlxText(20, 15 + 64, FlxG.width - 40, '${PlayState.instance?.deathCounter} Blue Balls'); + metadataDeaths = new FlxText(20, metadataDifficulty.y + 32, FlxG.width - 40, '${PlayState.instance?.deathCounter} Blue Balls'); metadataDeaths.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT); metadataDeaths.scrollFactor.set(0, 0); metadata.add(metadataDeaths); - metadataPractice = new FlxText(20, 15 + 96, FlxG.width - 40, 'PRACTICE MODE'); + metadataPractice = new FlxText(20, metadataDeaths.y + 32, FlxG.width - 40, 'PRACTICE MODE'); metadataPractice.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT); metadataPractice.visible = PlayState.instance?.isPracticeMode ?? false; metadataPractice.scrollFactor.set(0, 0); @@ -302,6 +325,62 @@ class PauseSubState extends MusicBeatSubState updateMetadataText(); } + var charterFadeTween:Null = null; + + function startCharterTimer():Void + { + charterFadeTween = FlxTween.tween(metadataArtist, {alpha: 0.0}, CHARTER_FADE_DURATION, + { + startDelay: CHARTER_FADE_DELAY, + ease: FlxEase.quartOut, + onComplete: (_) -> { + if (PlayState.instance?.currentChart != null) + { + metadataArtist.text = 'Charter: ${PlayState.instance.currentChart.charter ?? 'Unknown'}'; + } + else + { + metadataArtist.text = 'Charter: ${Constants.DEFAULT_CHARTER}'; + } + + FlxTween.tween(metadataArtist, {alpha: 1.0}, CHARTER_FADE_DURATION, + { + ease: FlxEase.quartOut, + onComplete: (_) -> { + startArtistTimer(); + } + }); + } + }); + } + + function startArtistTimer():Void + { + charterFadeTween = FlxTween.tween(metadataArtist, {alpha: 0.0}, CHARTER_FADE_DURATION, + { + startDelay: CHARTER_FADE_DELAY, + ease: FlxEase.quartOut, + onComplete: (_) -> { + if (PlayState.instance?.currentChart != null) + { + metadataArtist.text = 'Artist: ${PlayState.instance.currentChart.songArtist}'; + } + else + { + metadataArtist.text = 'Artist: ${Constants.DEFAULT_ARTIST}'; + } + + FlxTween.tween(metadataArtist, {alpha: 1.0}, CHARTER_FADE_DURATION, + { + ease: FlxEase.quartOut, + onComplete: (_) -> { + startCharterTimer(); + } + }); + } + }); + } + /** * Perform additional animations to transition the pause menu in when it is first displayed. */ diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 23d8d219..5da78e9d 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -120,6 +120,18 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry 0) return _metadata.get(Constants.DEFAULT_VARIATION)?.charter ?? 'Unknown'; + return Constants.DEFAULT_CHARTER; + } + /** * @param id The ID of the song to load. * @param ignoreErrors If false, an exception will be thrown if the song data could not be loaded. @@ -270,6 +282,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry = null; public var looped:Bool = false; diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index a313981f..980f5db4 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -1270,7 +1270,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var result:Null = songMetadata.get(selectedVariation); if (result == null) { - result = new SongMetadata('DadBattle', 'Kawai Sprite', selectedVariation); + result = new SongMetadata('Default Song Name', Constants.DEFAULT_ARTIST, selectedVariation); songMetadata.set(selectedVariation, result); } return result; diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx index f85307c6..80a421d8 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorMetadataToolbox.hx @@ -29,6 +29,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox { var inputSongName:TextField; var inputSongArtist:TextField; + var inputSongCharter:TextField; var inputStage:DropDown; var inputNoteStyle:DropDown; var buttonCharacterPlayer:Button; @@ -89,6 +90,20 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox } }; + inputSongCharter.onChange = function(event:UIEvent) { + var valid:Bool = event.target.text != null && event.target.text != ''; + + if (valid) + { + inputSongCharter.removeClass('invalid-value'); + chartEditorState.currentSongMetadata.charter = event.target.text; + } + else + { + chartEditorState.currentSongMetadata.charter = null; + } + }; + inputStage.onChange = function(event:UIEvent) { var valid:Bool = event.data != null && event.data.id != null; @@ -176,6 +191,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox inputSongName.value = chartEditorState.currentSongMetadata.songName; inputSongArtist.value = chartEditorState.currentSongMetadata.artist; + inputSongCharter.value = chartEditorState.currentSongMetadata.charter; inputStage.value = chartEditorState.currentSongMetadata.playData.stage; inputNoteStyle.value = chartEditorState.currentSongMetadata.playData.noteStyle; inputBPM.value = chartEditorState.currentSongMetadata.timeChanges[0].bpm; diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 2f3b570b..4e706c61 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -248,6 +248,11 @@ class Constants */ public static final DEFAULT_ARTIST:String = 'Unknown'; + /** + * The default charter for songs. + */ + public static final DEFAULT_CHARTER:String = 'Unknown'; + /** * The default note style for songs. */ From 13595fca700d99c0a472687b20b1ba6170eec58f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sun, 19 May 2024 01:49:06 -0400 Subject: [PATCH 015/131] Changelog entry for chart metadata --- source/funkin/data/song/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/funkin/data/song/CHANGELOG.md b/source/funkin/data/song/CHANGELOG.md index 3cd3af07..4f1c66ad 100644 --- a/source/funkin/data/song/CHANGELOG.md +++ b/source/funkin/data/song/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.2.3] +### Added +- Added `charter` field to denote authorship of a chart. + ## [2.2.2] ### Added - Added `playData.previewStart` and `playData.previewEnd` fields to specify when in the song should the song's audio should be played as a preview in Freeplay. From 9968c8eabcd6ee6b805abee3a3dbd9c82695fc89 Mon Sep 17 00:00:00 2001 From: etvx86 <64978924+EnterTheVoid-x86@users.noreply.github.com> Date: Mon, 20 May 2024 10:42:17 -0400 Subject: [PATCH 016/131] Fix some trace typos --- source/funkin/play/PlayState.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index a9ca09ce..88fea72a 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -772,19 +772,19 @@ class PlayState extends MusicBeatSubState var message:String = 'There was a critical error. Click OK to return to the main menu.'; if (currentSong == null) { - message = 'The was a critical error loading this song\'s chart. Click OK to return to the main menu.'; + message = 'There was a critical error loading this song\'s chart. Click OK to return to the main menu.'; } else if (currentDifficulty == null) { - message = 'The was a critical error selecting a difficulty for this song. Click OK to return to the main menu.'; + message = 'There was a critical error selecting a difficulty for this song. Click OK to return to the main menu.'; } else if (currentChart == null) { - message = 'The was a critical error retrieving data for this song on "$currentDifficulty" difficulty with variation "$currentVariation". Click OK to return to the main menu.'; + message = 'There was a critical error retrieving data for this song on "$currentDifficulty" difficulty with variation "$currentVariation". Click OK to return to the main menu.'; } else if (currentChart.notes == null) { - message = 'The was a critical error retrieving note data for this song on "$currentDifficulty" difficulty with variation "$currentVariation". Click OK to return to the main menu.'; + message = 'There was a critical error retrieving note data for this song on "$currentDifficulty" difficulty with variation "$currentVariation". Click OK to return to the main menu.'; } // Display a popup. This blocks the application until the user clicks OK. From f3868c2ee8d9dcf9488c349d8509545f0113f010 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 21 May 2024 02:23:21 -0400 Subject: [PATCH 017/131] An attempt at an HTML5 save data fix --- hmm.json | 2 +- source/funkin/save/Save.hx | 6 ++-- .../funkin/save/migrator/SaveDataMigrator.hx | 7 ++-- source/funkin/util/StructureUtil.hx | 32 ++++++++++++++++--- source/funkin/util/VersionUtil.hx | 19 +++++++++++ 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/hmm.json b/hmm.json index c359d7a5..1fe5a923 100644 --- a/hmm.json +++ b/hmm.json @@ -153,7 +153,7 @@ "name": "polymod", "type": "git", "dir": null, - "ref": "8553b800965f225bb14c7ab8f04bfa9cdec362ac", + "ref": "bfbe30d81601b3543d80dce580108ad6b7e182c7", "url": "https://github.com/larsiusprime/polymod" }, { diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index acbe59ed..dbba4a4c 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -53,7 +53,8 @@ class Save public function new(?data:RawSaveData) { if (data == null) this.data = Save.getDefault(); - else this.data = data; + else + this.data = data; } public static function getDefault():RawSaveData @@ -714,6 +715,7 @@ class Save /** * An anonymous structure containingg all the user's save data. + * Isn't stored with JSON, stored with some sort of Haxe built-in serialization? */ typedef RawSaveData = { @@ -724,8 +726,6 @@ typedef RawSaveData = /** * A semantic versioning string for the save data format. */ - @:jcustomparse(funkin.data.DataParse.semverVersion) - @:jcustomwrite(funkin.data.DataWrite.semverVersion) var version:Version; var api:SaveApiData; diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index 3ed59e72..7f597b4e 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -24,6 +24,8 @@ class SaveDataMigrator } else { + // Sometimes the Haxe serializer has issues with the version so we fix it here. + version = VersionUtil.repairVersion(version); if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE)) { // Simply import the structured data. @@ -32,8 +34,9 @@ class SaveDataMigrator } else { - trace('[SAVE] Invalid save data version! Returning blank data.'); - trace(inputData); + var message:String = 'Error migrating save data, expected ${Save.SAVE_DATA_VERSION}.'; + lime.app.Application.current.window.alert(message, "Save Data Failure"); + trace('[SAVE] ' + message); return new Save(Save.getDefault()); } } diff --git a/source/funkin/util/StructureUtil.hx b/source/funkin/util/StructureUtil.hx index 2f0c3818..2a6b345d 100644 --- a/source/funkin/util/StructureUtil.hx +++ b/source/funkin/util/StructureUtil.hx @@ -44,8 +44,15 @@ class StructureUtil return Std.isOfType(a, haxe.Constraints.IMap); } - public static function isObject(a:Dynamic):Bool + /** + * Returns `true` if `a` is an anonymous structure. + * I believe this returns `false` even for class instances and arrays. + */ + public static function isStructure(a:Dynamic):Bool { + // TODO: Is there a difference? + // return Reflect.isObject(foo); + switch (Type.typeof(a)) { case TObject: @@ -55,6 +62,22 @@ class StructureUtil } } + /** + * Returns true if `a` is an array. + * + * NOTE: isObject and isInstance also return true, + * since they're objects of the Array<> class, so check this first! + */ + public static function isArray(a:Dynamic):Bool + { + return Std.is(a, Array); + } + + public static function isInstance(a:Dynamic):Bool + { + return Type.getClass(a) != null; + } + public static function isPrimitive(a:Dynamic):Bool { switch (Type.typeof(a)) @@ -89,6 +112,7 @@ class StructureUtil { if (a == null) return b; if (b == null) return null; + if (isArray(a) && isArray(b)) return b; if (isPrimitive(a) && isPrimitive(b)) return b; if (isMap(b)) { @@ -101,7 +125,6 @@ class StructureUtil return StructureUtil.toMap(a).merge(b); } } - if (!Reflect.isObject(a) || !Reflect.isObject(b)) return b; if (Std.isOfType(b, haxe.ds.StringMap)) { if (Std.isOfType(a, haxe.ds.StringMap)) @@ -113,15 +136,14 @@ class StructureUtil return StructureUtil.toMap(a).merge(b); } } + if (!isStructure(a) || !isStructure(b)) return b; var result:DynamicAccess = Reflect.copy(a); for (field in Reflect.fields(b)) { - if (Reflect.isObject(b)) + if (isStructure(b)) { - // Note that isObject also returns true for class instances, - // but we just assume that's not a problem here. result.set(field, deepMerge(Reflect.field(result, field), Reflect.field(b, field))); } else diff --git a/source/funkin/util/VersionUtil.hx b/source/funkin/util/VersionUtil.hx index 247ba19d..8f555066 100644 --- a/source/funkin/util/VersionUtil.hx +++ b/source/funkin/util/VersionUtil.hx @@ -32,6 +32,25 @@ class VersionUtil } } + public static function repairVersion(version:thx.semver.Version):thx.semver.Version + { + var versionData:thx.semver.Version.SemVer = version; + + if (StructureUtil.isStructure(versionData.version)) + { + // This is bad! versionData.version should be an array! + versionData.version = [versionData.version[0], versionData.version[1], versionData.version[2]]; + + var fixedVersion:thx.semver.Version = versionData; + return fixedVersion; + } + else + { + // No need for repair. + return version; + } + } + /** * Checks that a given verison number satisisfies a given version rule. * Version rule can be complex, e.g. "1.0.x" or ">=1.0.0,<1.1.0", or anything NPM supports. From 6cb58163787b6951fa6fffed01a48e444cd5b5f5 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 21 May 2024 02:49:07 -0400 Subject: [PATCH 018/131] Add freeplay favorites to the save data so they persist between sessions. --- source/funkin/input/Controls.hx | 2 +- source/funkin/save/Save.hx | 44 ++++++++++++++++++++-- source/funkin/save/changelog.md | 3 ++ source/funkin/ui/freeplay/FreeplayState.hx | 25 +++++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx index 1983d413..cede0b68 100644 --- a/source/funkin/input/Controls.hx +++ b/source/funkin/input/Controls.hx @@ -707,7 +707,7 @@ class Controls extends FlxActionSet case Control.VOLUME_UP: return [PLUS, NUMPADPLUS]; case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS]; case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO]; - case Control.FULLSCREEN: return [FlxKey.F]; + case Control.FULLSCREEN: return [FlxKey.F11]; // We use F for other things LOL. } case Duo(true): diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index acbe59ed..7b2d3f51 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -14,8 +14,7 @@ import funkin.util.SerializerUtil; @:nullSafety class Save { - // Version 2.0.2 adds attributes to `optionsChartEditor`, that should return default values if they are null. - public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.3"; + public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.4"; public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x"; // We load this version's saves from a new save path, to maintain SOME level of backwards compatibility. @@ -53,7 +52,8 @@ class Save public function new(?data:RawSaveData) { if (data == null) this.data = Save.getDefault(); - else this.data = data; + else + this.data = data; } public static function getDefault():RawSaveData @@ -77,6 +77,9 @@ class Save levels: [], songs: [], }, + + favoriteSongs: [], + options: { // Reasonable defaults. @@ -554,6 +557,35 @@ class Save return false; } + public function isSongFavorited(id:String):Bool + { + if (data.favoriteSongs == null) + { + data.favoriteSongs = []; + flush(); + }; + + return data.favoriteSongs.contains(id); + } + + public function favoriteSong(id:String):Void + { + if (!isSongFavorited(id)) + { + data.favoriteSongs.push(id); + flush(); + } + } + + public function unfavoriteSong(id:String):Void + { + if (isSongFavorited(id)) + { + data.favoriteSongs.remove(id); + flush(); + } + } + public function getControls(playerId:Int, inputType:Device):Null { switch (inputType) @@ -740,6 +772,12 @@ typedef RawSaveData = */ var options:SaveDataOptions; + /** + * The user's favorited songs in the Freeplay menu, + * as a list of song IDs. + */ + var favoriteSongs:Array; + var mods:SaveDataMods; /** diff --git a/source/funkin/save/changelog.md b/source/funkin/save/changelog.md index 3fa9839d..7c9094f2 100644 --- a/source/funkin/save/changelog.md +++ b/source/funkin/save/changelog.md @@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.4] - 2024-05-21 +### Added +- `favoriteSongs:Array` to `Save` ## [2.0.3] - 2024-01-09 ### Added diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 23906828..911d07a5 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -699,8 +699,8 @@ class FreeplayState extends MusicBeatSubState if (targetSong != null) { var realShit:Int = curSelected; - targetSong.isFav = !targetSong.isFav; - if (targetSong.isFav) + var isFav = targetSong.toggleFavorite(); + if (isFav) { FlxTween.tween(grpCapsules.members[realShit], {angle: 360}, 0.4, { @@ -1398,11 +1398,32 @@ class FreeplaySongData this.levelId = levelId; this.songId = songId; this.song = song; + + this.isFav = Save.instance.isSongFavorited(songId); + if (displayedVariations != null) this.displayedVariations = displayedVariations; updateValues(displayedVariations); } + /** + * Toggle whether or not the song is favorited, then flush to save data. + * @return Whether or not the song is now favorited. + */ + public function toggleFavorite():Bool + { + isFav = !isFav; + if (isFav) + { + Save.instance.favoriteSong(this.songId); + } + else + { + Save.instance.unfavoriteSong(this.songId); + } + return isFav; + } + function updateValues(variations:Array):Void { this.songDifficulties = song.listDifficulties(variations, false, false); From fed6d1146c67b048f2c9b82d3b50a7dd9cd1748f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 21 May 2024 04:02:32 -0400 Subject: [PATCH 019/131] Do some cleanup (replace several utility functions with a utility library we already depend on!) --- Project.xml | 1 + source/funkin/import.hx | 1 + source/funkin/play/song/Song.hx | 16 +- .../funkin/save/migrator/SaveDataMigrator.hx | 5 +- source/funkin/ui/story/LevelProp.hx | 5 +- source/funkin/util/StructureUtil.hx | 158 ------------------ source/funkin/util/tools/ArrayTools.hx | 66 -------- 7 files changed, 17 insertions(+), 235 deletions(-) delete mode 100644 source/funkin/util/StructureUtil.hx diff --git a/Project.xml b/Project.xml index fcfcfb9f..b5630a46 100644 --- a/Project.xml +++ b/Project.xml @@ -128,6 +128,7 @@ + diff --git a/source/funkin/import.hx b/source/funkin/import.hx index 250de99c..c8431be3 100644 --- a/source/funkin/import.hx +++ b/source/funkin/import.hx @@ -11,6 +11,7 @@ import flixel.system.debug.watch.Tracker; // These are great. using Lambda; using StringTools; +using thx.Arrays; using funkin.util.tools.ArraySortTools; using funkin.util.tools.ArrayTools; using funkin.util.tools.FloatTools; diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 23d8d219..53408fb3 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -439,12 +439,16 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry = difficulties.keys().array().map(function(diffId:String):Null { - var difficulty:Null = difficulties.get(diffId); - if (difficulty == null) return null; - if (variationIds.length > 0 && !variationIds.contains(difficulty.variation)) return null; - return difficulty.difficulty; - }).nonNull().unique(); + var diffFiltered:Array = difficulties.keys() + .array() + .map(function(diffId:String):Null { + var difficulty:Null = difficulties.get(diffId); + if (difficulty == null) return null; + if (variationIds.length > 0 && !variationIds.contains(difficulty.variation)) return null; + return difficulty.difficulty; + }) + .filterNull() + .distinct(); diffFiltered = diffFiltered.filter(function(diffId:String):Bool { if (showHidden) return true; diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index 7f597b4e..5398b211 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -28,8 +28,9 @@ class SaveDataMigrator version = VersionUtil.repairVersion(version); if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE)) { - // Simply import the structured data. - var save:Save = new Save(StructureUtil.deepMerge(Save.getDefault(), inputData)); + // Import the structured data. + var saveDataWithDefaults:RawSaveData = thx.Objects.deepCombine(Save.getDefault(), inputData); + var save:Save = new Save(saveDataWithDefaults); return save; } else diff --git a/source/funkin/ui/story/LevelProp.hx b/source/funkin/ui/story/LevelProp.hx index ffc756e1..5a3efc36 100644 --- a/source/funkin/ui/story/LevelProp.hx +++ b/source/funkin/ui/story/LevelProp.hx @@ -13,11 +13,10 @@ class LevelProp extends Bopper // Only reset the prop if the asset path has changed. if (propData == null || value?.assetPath != propData?.assetPath) { - this.visible = (value != null); - this.propData = value; - danceEvery = this.propData?.danceEvery ?? 0; applyData(); } + this.visible = (value != null); + danceEvery = this.propData?.danceEvery ?? 0; return this.propData; } diff --git a/source/funkin/util/StructureUtil.hx b/source/funkin/util/StructureUtil.hx deleted file mode 100644 index 2a6b345d..00000000 --- a/source/funkin/util/StructureUtil.hx +++ /dev/null @@ -1,158 +0,0 @@ -package funkin.util; - -import funkin.util.tools.MapTools; -import haxe.DynamicAccess; - -/** - * Utilities for working with anonymous structures. - */ -class StructureUtil -{ - /** - * Merge two structures, with the second overwriting the first. - * Performs a SHALLOW clone, where child structures are not merged. - * @param a The base structure. - * @param b The new structure. - * @return The merged structure. - */ - public static function merge(a:Dynamic, b:Dynamic):Dynamic - { - var result:DynamicAccess = Reflect.copy(a); - - for (field in Reflect.fields(b)) - { - result.set(field, Reflect.field(b, field)); - } - - return result; - } - - public static function toMap(a:Dynamic):haxe.ds.Map - { - var result:haxe.ds.Map = []; - - for (field in Reflect.fields(a)) - { - result.set(field, Reflect.field(a, field)); - } - - return result; - } - - public static function isMap(a:Dynamic):Bool - { - return Std.isOfType(a, haxe.Constraints.IMap); - } - - /** - * Returns `true` if `a` is an anonymous structure. - * I believe this returns `false` even for class instances and arrays. - */ - public static function isStructure(a:Dynamic):Bool - { - // TODO: Is there a difference? - // return Reflect.isObject(foo); - - switch (Type.typeof(a)) - { - case TObject: - return true; - default: - return false; - } - } - - /** - * Returns true if `a` is an array. - * - * NOTE: isObject and isInstance also return true, - * since they're objects of the Array<> class, so check this first! - */ - public static function isArray(a:Dynamic):Bool - { - return Std.is(a, Array); - } - - public static function isInstance(a:Dynamic):Bool - { - return Type.getClass(a) != null; - } - - public static function isPrimitive(a:Dynamic):Bool - { - switch (Type.typeof(a)) - { - case TInt | TFloat | TBool: - return true; - case TClass(c): - return false; - case TEnum(e): - return false; - case TObject: - return false; - case TFunction: - return false; - case TNull: - return true; - case TUnknown: - return false; - default: - return false; - } - } - - /** - * Merge two structures, with the second overwriting the first. - * Performs a DEEP clone, where child structures are also merged recursively. - * @param a The base structure. - * @param b The new structure. - * @return The merged structure. - */ - public static function deepMerge(a:Dynamic, b:Dynamic):Dynamic - { - if (a == null) return b; - if (b == null) return null; - if (isArray(a) && isArray(b)) return b; - if (isPrimitive(a) && isPrimitive(b)) return b; - if (isMap(b)) - { - if (isMap(a)) - { - return MapTools.merge(a, b); - } - else - { - return StructureUtil.toMap(a).merge(b); - } - } - if (Std.isOfType(b, haxe.ds.StringMap)) - { - if (Std.isOfType(a, haxe.ds.StringMap)) - { - return MapTools.merge(a, b); - } - else - { - return StructureUtil.toMap(a).merge(b); - } - } - if (!isStructure(a) || !isStructure(b)) return b; - - var result:DynamicAccess = Reflect.copy(a); - - for (field in Reflect.fields(b)) - { - if (isStructure(b)) - { - result.set(field, deepMerge(Reflect.field(result, field), Reflect.field(b, field))); - } - else - { - // If we're here, b[field] is a primitive. - result.set(field, Reflect.field(b, field)); - } - } - - return result; - } -} diff --git a/source/funkin/util/tools/ArrayTools.hx b/source/funkin/util/tools/ArrayTools.hx index caf8e8aa..0fe245e3 100644 --- a/source/funkin/util/tools/ArrayTools.hx +++ b/source/funkin/util/tools/ArrayTools.hx @@ -5,72 +5,6 @@ package funkin.util.tools; */ class ArrayTools { - /** - * Returns a copy of the array with all duplicate elements removed. - * @param array The array to remove duplicates from. - * @return A copy of the array with all duplicate elements removed. - */ - public static function unique(array:Array):Array - { - var result:Array = []; - for (element in array) - { - if (!result.contains(element)) - { - result.push(element); - } - } - return result; - } - - /** - * Returns a copy of the array with all `null` elements removed. - * @param array The array to remove `null` elements from. - * @return A copy of the array with all `null` elements removed. - */ - public static function nonNull(array:Array>):Array - { - var result:Array = []; - for (element in array) - { - if (element != null) - { - result.push(element); - } - } - return result; - } - - /** - * Return the first element of the array that satisfies the predicate, or null if none do. - * @param input The array to search - * @param predicate The predicate to call - * @return The result - */ - public static function find(input:Array, predicate:T->Bool):Null - { - for (element in input) - { - if (predicate(element)) return element; - } - return null; - } - - /** - * Return the index of the first element of the array that satisfies the predicate, or `-1` if none do. - * @param input The array to search - * @param predicate The predicate to call - * @return The index of the result - */ - public static function findIndex(input:Array, predicate:T->Bool):Int - { - for (index in 0...input.length) - { - if (predicate(input[index])) return index; - } - return -1; - } - /* * Push an element to the array if it is not already present. * @param input The array to push to From 6d3b58cecdb3b3881e261a3137518926835fd7a5 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 21 May 2024 04:02:53 -0400 Subject: [PATCH 020/131] Fix some additional compiling issues. --- source/funkin/save/migrator/SaveDataMigrator.hx | 3 +-- source/funkin/util/VersionUtil.hx | 2 +- source/funkin/util/macro/InlineMacro.hx | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index 5398b211..650666c5 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -3,7 +3,6 @@ package funkin.save.migrator; import funkin.save.Save; import funkin.save.migrator.RawSaveData_v1_0_0; import thx.semver.Version; -import funkin.util.StructureUtil; import funkin.util.VersionUtil; @:nullSafety @@ -29,7 +28,7 @@ class SaveDataMigrator if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE)) { // Import the structured data. - var saveDataWithDefaults:RawSaveData = thx.Objects.deepCombine(Save.getDefault(), inputData); + var saveDataWithDefaults:RawSaveData = cast thx.Objects.deepCombine(Save.getDefault(), inputData); var save:Save = new Save(saveDataWithDefaults); return save; } diff --git a/source/funkin/util/VersionUtil.hx b/source/funkin/util/VersionUtil.hx index 8f555066..18d7eafa 100644 --- a/source/funkin/util/VersionUtil.hx +++ b/source/funkin/util/VersionUtil.hx @@ -36,7 +36,7 @@ class VersionUtil { var versionData:thx.semver.Version.SemVer = version; - if (StructureUtil.isStructure(versionData.version)) + if (thx.Types.isAnonymousObject(versionData.version)) { // This is bad! versionData.version should be an array! versionData.version = [versionData.version[0], versionData.version[1], versionData.version[2]]; diff --git a/source/funkin/util/macro/InlineMacro.hx b/source/funkin/util/macro/InlineMacro.hx index b0e7ed18..c4025740 100644 --- a/source/funkin/util/macro/InlineMacro.hx +++ b/source/funkin/util/macro/InlineMacro.hx @@ -23,7 +23,7 @@ class InlineMacro var fields:Array = haxe.macro.Context.getBuildFields(); // Find the field with the given name. - var targetField:Null = fields.find(function(f) return f.name == field + var targetField:Null = thx.Arrays.find(fields, function(f) return f.name == field && (MacroUtil.isFieldStatic(f) == isStatic)); // If the field was not found, throw an error. From f17f6393041a54e4b15418059f6a9ff9dc2a39cb Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 22 May 2024 01:07:20 -0400 Subject: [PATCH 021/131] Finish implementing smaller numbers. --- assets | 2 +- source/funkin/InitState.hx | 4 +- source/funkin/play/ResultState.hx | 75 ++++++++++++++++--- .../play/components/ClearPercentCounter.hx | 73 ++++++++++++++---- 4 files changed, 124 insertions(+), 30 deletions(-) diff --git a/assets b/assets index ce7dabff..b6d93010 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit ce7dabffbebc154c9dda1f01e92dbef83e3405ab +Subproject commit b6d930109eb69cfd368145e893d81ac1e97ed004 diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index 6a52eaf5..d17554d1 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -227,14 +227,14 @@ class InitState extends FlxState tallies: { sick: 130, - good: 69, + good: 70, bad: 69, shit: 69, missed: 69, combo: 69, maxCombo: 69, totalNotesHit: 140, - totalNotes: 2000, + totalNotes: 200 // 0, } }, })); diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index d038b778..fdcd0cc3 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -37,6 +37,7 @@ class ResultState extends MusicBeatSubState final rank:ResultRank; final songName:FlxBitmapText; final difficulty:FlxSprite; + final clearPercentSmall:ClearPercentCounter; final maskShaderSongName:LeftMaskShader = new LeftMaskShader(); final maskShaderDifficulty:LeftMaskShader = new LeftMaskShader(); @@ -78,6 +79,10 @@ class ResultState extends MusicBeatSubState difficulty = new FlxSprite(555); difficulty.zIndex = 1000; + clearPercentSmall = new ClearPercentCounter(FlxG.width / 2 + 300, FlxG.height / 2 - 100, 100, true); + clearPercentSmall.zIndex = 1000; + clearPercentSmall.visible = false; + bgFlash = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFEB69, 0xFFFFE66A], 90); resultsAnim = FunkinSprite.createSparrow(-200, -10, "resultScreen/results"); @@ -194,7 +199,7 @@ class ResultState extends MusicBeatSubState speedOfTween.x = -1.0 * Math.cos(angleRad); speedOfTween.y = -1.0 * Math.sin(angleRad); - timerThenSongName(1.0); + timerThenSongName(1.0, false); songName.shader = maskShaderSongName; difficulty.shader = maskShaderDifficulty; @@ -319,13 +324,15 @@ class ResultState extends MusicBeatSubState function startRankTallySequence():Void { - clearPercentTarget = Math.floor((params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100); - clearPercentTarget = 100; + var clearPercentFloat = (params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100; + clearPercentTarget = Math.floor(clearPercentFloat); + // Prevent off-by-one errors. clearPercentLerp = Std.int(Math.max(0, clearPercentTarget - 36)); - var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter(FlxG.width / 2 + 300, FlxG.height / 2 - 100, clearPercentTarget); - clearPercentCounter.curNumber = clearPercentLerp; + trace('Clear percent target: ' + clearPercentFloat + ', round: ' + clearPercentTarget); + + var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter(FlxG.width / 2 + 300, FlxG.height / 2 - 100, clearPercentLerp); FlxTween.tween(clearPercentCounter, {curNumber: clearPercentTarget}, 1.5, { ease: FlxEase.quartOut, @@ -345,10 +352,25 @@ class ResultState extends MusicBeatSubState bgFlash.visible = true; FlxTween.tween(bgFlash, {alpha: 0}, 0.4); + // Just to be sure that the lerp didn't mess things up. + clearPercentCounter.curNumber = clearPercentTarget; + + clearPercentCounter.flash(true); + new FlxTimer().start(0.4, _ -> { + clearPercentCounter.flash(false); + }); + displayRankText(); new FlxTimer().start(2.0, _ -> { - // remove(clearPercentCounter); + FlxTween.tween(clearPercentCounter, {alpha: 0}, 0.5, + { + startDelay: 0.5, + ease: FlxEase.quartOut, + onComplete: _ -> { + remove(clearPercentCounter); + } + }); afterRankTallySequence(); }); @@ -406,6 +428,8 @@ class ResultState extends MusicBeatSubState function afterRankTallySequence():Void { + showSmallClearPercent(); + FunkinSound.playMusic(rank.getMusicPath(), { startingVolume: 1.0, @@ -490,7 +514,7 @@ class ResultState extends MusicBeatSubState } } - function timerThenSongName(timerLength:Float = 3.0):Void + function timerThenSongName(timerLength:Float = 3.0, autoScroll:Bool = true):Void { movingSongStuff = false; @@ -501,10 +525,17 @@ class ResultState extends MusicBeatSubState difficulty.y = -difficulty.height; FlxTween.tween(difficulty, {y: diffYTween}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.8}); + if (clearPercentSmall != null) + { + clearPercentSmall.x = (difficulty.x + difficulty.width) + 60; + clearPercentSmall.y = -clearPercentSmall.height; + FlxTween.tween(clearPercentSmall, {y: 122 - 5}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.8}); + } + songName.y = -songName.height; var fuckedupnumber = (10) * (songName.text.length / 15); - FlxTween.tween(songName, {y: diffYTween - 35 - fuckedupnumber}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9}); - songName.x = (difficulty.x + difficulty.width) + 20; + FlxTween.tween(songName, {y: diffYTween - 25 - fuckedupnumber}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9}); + songName.x = clearPercentSmall.x + clearPercentSmall.width - 30; new FlxTimer().start(timerLength, _ -> { var tempSpeed = FlxPoint.get(speedOfTween.x, speedOfTween.y); @@ -512,10 +543,29 @@ class ResultState extends MusicBeatSubState speedOfTween.set(0, 0); FlxTween.tween(speedOfTween, {x: tempSpeed.x, y: tempSpeed.y}, 0.7, {ease: FlxEase.quadIn}); - movingSongStuff = true; + movingSongStuff = (autoScroll); }); } + function showSmallClearPercent():Void + { + if (clearPercentSmall != null) + { + add(clearPercentSmall); + clearPercentSmall.visible = true; + clearPercentSmall.flash(true); + new FlxTimer().start(0.4, _ -> { + clearPercentSmall.flash(false); + }); + + clearPercentSmall.curNumber = clearPercentTarget; + clearPercentSmall.zIndex = 1000; + refresh(); + } + + movingSongStuff = true; + } + var movingSongStuff:Bool = false; var speedOfTween:FlxPoint = FlxPoint.get(-1, 1); @@ -523,7 +573,8 @@ class ResultState extends MusicBeatSubState { super.draw(); - songName.clipRect = FlxRect.get(Math.max(0, 540 - songName.x), 0, FlxG.width, songName.height); + songName.clipRect = FlxRect.get(Math.max(0, 520 - songName.x), 0, FlxG.width, songName.height); + // PROBABLY SHOULD FIX MEMORY FREE OR WHATEVER THE PUT() FUNCTION DOES !!!! FEELS LIKE IT STUTTERS!!! // if (songName != null && songName.frame != null) @@ -539,8 +590,10 @@ class ResultState extends MusicBeatSubState { songName.x += speedOfTween.x; difficulty.x += speedOfTween.x; + clearPercentSmall.x += speedOfTween.x; songName.y += speedOfTween.y; difficulty.y += speedOfTween.y; + clearPercentSmall.y += speedOfTween.y; if (songName.x + songName.width < 100) { diff --git a/source/funkin/play/components/ClearPercentCounter.hx b/source/funkin/play/components/ClearPercentCounter.hx index 4c03ec3a..d296b0b0 100644 --- a/source/funkin/play/components/ClearPercentCounter.hx +++ b/source/funkin/play/components/ClearPercentCounter.hx @@ -1,6 +1,7 @@ package funkin.play.components; import funkin.graphics.FunkinSprite; +import funkin.graphics.shaders.PureColor; import flixel.FlxSprite; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; @@ -9,25 +10,54 @@ import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.text.FlxText.FlxTextAlign; import funkin.util.MathUtil; +import flixel.util.FlxColor; /** * Numerical counters used to display the clear percent. */ class ClearPercentCounter extends FlxTypedSpriteGroup { - public var curNumber:Int = 0; - public var neededNumber:Int = 0; + public var curNumber(default, set):Int = 0; - public function new(x:Float, y:Float, neededNumber:Int = 0) + var numberChanged:Bool = false; + + function set_curNumber(val:Int):Int + { + numberChanged = true; + return curNumber = val; + } + + var small:Bool = false; + var flashShader:PureColor; + + public function new(x:Float, y:Float, startingNumber:Int = 0, small:Bool = false) { super(x, y); - this.neededNumber = neededNumber; + flashShader = new PureColor(FlxColor.WHITE); + flashShader.colorSet = true; - var clearPercentText:FunkinSprite = FunkinSprite.create(0, 0, 'resultScreen/clearPercent/clearPercentText'); + curNumber = startingNumber; + + this.small = small; + + var clearPercentText:FunkinSprite = FunkinSprite.create(0, 0, 'resultScreen/clearPercent/clearPercentText${small ? 'Small' : ''}'); + clearPercentText.x = small ? 40 : 0; add(clearPercentText); - if (curNumber == neededNumber) drawNumbers(); + drawNumbers(); + } + + /** + * Make the counter flash turn white or stop being all white. + * @param enabled Whether the counter should be white. + */ + public function flash(enabled:Bool):Void + { + for (member in members) + { + member.shader = enabled ? flashShader : null; + } } var tmr:Float = 0; @@ -36,7 +66,7 @@ class ClearPercentCounter extends FlxTypedSpriteGroup { super.update(elapsed); - if (curNumber < neededNumber) drawNumbers(); + if (numberChanged) drawNumbers(); } function drawNumbers() @@ -44,8 +74,6 @@ class ClearPercentCounter 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); @@ -59,19 +87,32 @@ class ClearPercentCounter extends FlxTypedSpriteGroup for (ind => num in seperatedScore) { var digitIndex = ind + 1; + // If there's only one digit, move it to the right + // If there's three digits, move them all to the left + var digitOffset = (seperatedScore.length == 1) ? 1 : (seperatedScore.length == 3) ? -1 : 0; + var digitSize = small ? 32 : 72; + var digitHeightOffset = small ? -4 : 0; + + var xPos = (digitIndex - 1 + digitOffset) * (digitSize * this.scale.x); + xPos += small ? -24 : 0; + var yPos = (digitIndex - 1 + digitOffset) * (digitHeightOffset * this.scale.y); + yPos += small ? 0 : 72; + if (digitIndex >= members.length) { - var xPos = (digitIndex - 1) * (72 * this.scale.x); - var yPos = 72; - // Three digits = LRL so two different numbers aren't adjacent to each other. - var variant:Bool = (fullNumberDigits % 2 != 0) ? (digitIndex % 2 == 0) : (digitIndex % 2 == 1); - var numb:ClearPercentNumber = new ClearPercentNumber(xPos, yPos, num); + // Three digits = LLR because the 1 and 0 won't be the same anyway. + var variant:Bool = (seperatedScore.length == 3) ? (digitIndex >= 2) : (digitIndex >= 1); + // var variant:Bool = (seperatedScore.length % 2 != 0) ? (digitIndex % 2 == 0) : (digitIndex % 2 == 1); + var numb:ClearPercentNumber = new ClearPercentNumber(xPos, yPos, num, variant, this.small); numb.scale.set(this.scale.x, this.scale.y); add(numb); } else { members[digitIndex].animation.play(Std.string(num)); + // Reset the position of the number + members[digitIndex].x = xPos + this.x; + members[digitIndex].y = yPos + this.y; } } } @@ -79,11 +120,11 @@ class ClearPercentCounter extends FlxTypedSpriteGroup class ClearPercentNumber extends FlxSprite { - public function new(x:Float, y:Float, digit:Int, variant:Bool = false) + public function new(x:Float, y:Float, digit:Int, variant:Bool, small:Bool) { super(x, y); - frames = Paths.getSparrowAtlas('resultScreen/clearPercent/clearPercentNumber${variant ? 'Right' : 'Left'}'); + frames = Paths.getSparrowAtlas('resultScreen/clearPercent/clearPercentNumber${small ? 'Small' : variant ? 'Right' : 'Left'}'); for (i in 0...10) { From 9afc314a0d20f29d69beba70d91d23cc37922660 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 22 May 2024 15:20:53 -0400 Subject: [PATCH 022/131] Fix an issue with git modules --- .gitmodules | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index be5e0aaa..2d5c1106 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,5 @@ [submodule "assets"] path = assets - url = https://github.com/FunkinCrew/funkin.assets -[submodule "art"] + url = https://github.com/FunkinCrew/Funkin-Assets-secret path = art - url = https://github.com/FunkinCrew/funkin.art + url = https://github.com/FunkinCrew/Funkin-Art-secret From a2ee359e466746646c278d0adbef0c1fd08d21c1 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 23 May 2024 16:31:18 -0400 Subject: [PATCH 023/131] fix for songs overlapping each other on desktop --- source/funkin/audio/FunkinSound.hx | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 5a49e29e..aaddda9d 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -364,10 +364,20 @@ class FunkinSound extends FlxSound implements ICloneable if (music != null) { + for (future in partialQueue) + { + future = cast Future.withError("Music was overridden by another partial load"); + } + partialQueue = []; + partialQueue.push(music); + + @:nullSafety(Off) music.onComplete(function(partialMusic:Null) { - @:nullSafety(Off) - FlxG.sound.music = partialMusic; - FlxG.sound.list.remove(FlxG.sound.music); + if (partialQueue.pop() == music) + { + FlxG.sound.music = partialMusic; + FlxG.sound.list.remove(FlxG.sound.music); + } }); return true; @@ -396,6 +406,8 @@ class FunkinSound extends FlxSound implements ICloneable } } + static var partialQueue:Array>> = []; + /** * Creates a new `FunkinSound` object synchronously. * @@ -461,6 +473,8 @@ class FunkinSound extends FlxSound implements ICloneable * @param looped Whether the sound file should loop * @param autoDestroy Whether the sound file should be destroyed after it finishes playing * @param autoPlay Whether the sound file should play immediately + * @param onComplete Callback when the sound finishes playing + * @param onLoad Callback when the sound finishes loading * @return A FunkinSound object */ public static function loadPartial(path:String, start:Float = 0, end:Float = 1, volume:Float = 1.0, looped:Bool = false, autoDestroy:Bool = false, From 44880fa5697ddf16a62211cd4089d63371acaf46 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 May 2024 00:06:26 -0400 Subject: [PATCH 024/131] Implement placeholder GREAT animation --- source/funkin/InitState.hx | 2 +- source/funkin/play/ResultState.hx | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index d17554d1..a945c10c 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -227,7 +227,7 @@ class InitState extends FlxState tallies: { sick: 130, - good: 70, + good: 25, bad: 69, shit: 69, missed: 69, diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index fdcd0cc3..ee7c8ead 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -53,6 +53,7 @@ class ResultState extends MusicBeatSubState var bfPerfect:Null = null; var bfExcellent:Null = null; + var bfGreat:Null = null; var bfGood:Null = null; var gfGood:Null = null; var bfShit:Null = null; @@ -151,7 +152,20 @@ class ResultState extends MusicBeatSubState } }); - case GOOD | GREAT: + case GREAT: + bfGreat = new FlxAtlasSprite(640, 200, Paths.animateAtlas("resultScreen/results-bf/resultsGREAT", "shared")); + bfGreat.visible = false; + bfGreat.zIndex = 500; + add(bfGreat); + + bfGreat.onAnimationFinish.add((animName) -> { + if (bfGreat != null) + { + bfGreat.playAnimation('Loop Start'); + } + }); + + case GOOD: gfGood = FunkinSprite.createSparrow(625, 325, 'resultScreen/results-bf/resultsGOOD/resultGirlfriendGOOD'); gfGood.animation.addByPrefix("clap", "Girlfriend Good Anim", 24, false); gfGood.visible = false; @@ -476,6 +490,17 @@ class ResultState extends MusicBeatSubState bfExcellent.playAnimation('Intro'); } + case GREAT: + if (bfGreat == null) + { + trace("Could not build GREAT animation!"); + } + else + { + bfGreat.visible = true; + bfGreat.playAnimation('Intro'); + } + case SHIT: if (bfShit == null) { @@ -487,7 +512,7 @@ class ResultState extends MusicBeatSubState bfShit.playAnimation('Intro'); } - case GREAT | GOOD: + case GOOD: if (bfGood == null) { trace("Could not build GOOD animation!"); From 2db99b3cb41bef826bd3a286ac0d942476dc5eee Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 May 2024 00:06:52 -0400 Subject: [PATCH 025/131] Update submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index b6d93010..2a57e340 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit b6d930109eb69cfd368145e893d81ac1e97ed004 +Subproject commit 2a57e34061f6034236663851332319c5dedab259 From 0e920237940d894ffb9be77f67f4d73a8463d1f3 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 May 2024 00:21:45 -0400 Subject: [PATCH 026/131] Add credits for all charts + tweak charts for Guns, Lit Up, Winter Horrorland --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 778e1670..826be3bf 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 778e16705b30af85087f627594c22f4b5ba6141a +Subproject commit 826be3bf1e635e6b61c8c11bd3ece51f8a2b3061 From 62e04b3372fe1b9f7256585a23ed38a5b51db98f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 May 2024 13:24:11 -0400 Subject: [PATCH 027/131] Update Changelog --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7f83004..10bbfe5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,46 @@ All notable changes will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.0] - 2024-05-?? +### Added +- 2 new Erect remixes, Eggnog and Satin Panties. Check them out from +- Improvements to the Freeplay screen, with song difficulty ratings and player rank displays. +- Reworked the Results screen, with additional animations and audio based on your performance. +- Added a Charter field to the chart format, to allow for crediting the creator of a level's chart. + - You can see who charted a song from the Pause menu. +### Changed +- Tweaked the charts for several songs: + - Winter Horrorland + - Stress + - Lit Up +- Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!) +- Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!) + - Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame. +### Fixed +- Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!) +- Fixed a bug where the Chart Editor would crash when losing (thanks gamerbross!) +- Made improvements to compiling documentation (thanks gedehari!) +- Fixed a crash on Linux caused by an old version of hxCodec (thanks Noobz4Life!) +- Optimized animation handling for characters (thanks richTrash21!) + +## [0.3.3] - 2024-05-14 +### Changed +- Cleaned up some code in `PlayAnimationSongEvent.hx` (thanks BurgerBalls!) +### Fixed +- Fix Web Loading Bar (thanks lemz1!) +- Don't allow any more inputs when exiting freeplay (thanks gamerbros!) +- Fixed using mouse wheel to scroll on freeplay (thanks JugieNoob!) +- Fixed the reset's of the health icons, score, and notes when re-entering gameplay from gameover (thanks ImCodist!) +- Fixed the chart editor character selector's hitbox width (thanks MadBear422!) +- Fixed camera stutter once a wipe transition to the Main Menu completes (thanks ImCodist!) +- Fixed an issue where hold note would be invisible for a single frame (thanks ImCodist!) +- Fix tween accumulation on title screen when pressing Y multiple times (thanks TheGaloXx!) +- Fix for a game over easter egg so you don't accidentally exit it when viewing +- Fix a crash when querying FlxG.state in the crash handler +- Fix an issue where the Freeplay menu never displays 100% clear +- Chart debug key now properly returns you to the previous chart editor session if you were playtesting a chart (thanks nebulazorua!) +- Hopefully fixed Freeplay crashes on AMD gpu's + ## [0.3.2] - 2024-05-03 ### Added - Added `,` and `.` keybinds to the Chart Editor. These place Focus Camera events at the playhead, for the opponent and player respectively. From c8930b598025f6f9faff795aeb3280ae3480c6b6 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 May 2024 13:45:37 -0400 Subject: [PATCH 028/131] Attempt to repair local submodules --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 2d5c1106..452c0089 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,6 @@ [submodule "assets"] path = assets url = https://github.com/FunkinCrew/Funkin-Assets-secret +[submodule "art"] path = art url = https://github.com/FunkinCrew/Funkin-Art-secret From 98505e58eca59a084bdd5fc98765ee53aca7c926 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 May 2024 14:04:55 -0400 Subject: [PATCH 029/131] Take two at fixing submodules --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 66572f85..52e007f5 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 66572f85d826ce2ec1d45468c12733b161237ffa +Subproject commit 52e007f5b682ee7b9d252edba78a88780510d32b From 85bfd00bade0d7413b578d7152afa6cc8f93f1d6 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 24 May 2024 16:38:35 -0400 Subject: [PATCH 030/131] desktop vis testing --- Project.xml | 1 + hmm.json | 9 ++++++++- source/funkin/audio/visualize/ABotVis.hx | 8 +++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Project.xml b/Project.xml index 24cdac27..03e87e2d 100644 --- a/Project.xml +++ b/Project.xml @@ -125,6 +125,7 @@ + diff --git a/hmm.json b/hmm.json index 288aa80b..a1998f51 100644 --- a/hmm.json +++ b/hmm.json @@ -49,9 +49,16 @@ "name": "funkin.vis", "type": "git", "dir": null, - "ref": "2aa654b974507ab51ab1724d2d97e75726fd7d78", + "ref": "c6a1e24d48646849ea63563ca45561512c953779", "url": "https://github.com/FunkinCrew/funkVis" }, + { + "name": "grig.audio", + "type": "git", + "dir": "src", + "ref": "cbf91e2180fd2e374924fe74844086aab7891666", + "url": "https://gitlab.com/haxe-grig/grig.audio.git" + }, { "name": "hamcrest", "type": "haxelib", diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index ca77dd58..15596318 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -58,8 +58,8 @@ class ABotVis extends FlxTypedSpriteGroup public function initAnalyzer() { @:privateAccess - analyzer = new SpectralAnalyzer(7, new LimeAudioClip(cast snd._channel.__source), 0.01, 30); - analyzer.maxDb = -35; + analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.01, 30); + // analyzer.maxDb = -35; // analyzer.fftN = 2048; } @@ -83,9 +83,7 @@ class ABotVis extends FlxTypedSpriteGroup override function draw() { - #if web if (analyzer != null) drawFFT(); - #end super.draw(); } @@ -94,7 +92,7 @@ class ABotVis extends FlxTypedSpriteGroup */ function drawFFT():Void { - var levels = analyzer.getLevels(false); + var levels = analyzer.getLevels(); for (i in 0...min(group.members.length, levels.length)) { From dd3e241f0c08ae5239ba081c1022acc96e993abe Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 May 2024 16:44:12 -0400 Subject: [PATCH 031/131] Fix some merge conflicts --- source/funkin/input/Controls.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx index 31551dec..345791ee 100644 --- a/source/funkin/input/Controls.hx +++ b/source/funkin/input/Controls.hx @@ -997,7 +997,7 @@ class Controls extends FlxActionSet for (control in Control.createAll()) { var inputs:Array = Reflect.field(data, control.getName()); - inputs = inputs.unique(); + inputs = inputs.distinct(); if (inputs != null) { if (inputs.length == 0) { @@ -1050,7 +1050,7 @@ class Controls extends FlxActionSet if (inputs.length == 0) { inputs = [FlxKey.NONE]; } else { - inputs = inputs.unique(); + inputs = inputs.distinct(); } Reflect.setField(data, control.getName(), inputs); From 6c0d998edd02f39863b840e5557fdb8375d367b5 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 28 May 2024 01:18:18 -0400 Subject: [PATCH 032/131] update funkVis in hmm --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index a1998f51..e364e405 100644 --- a/hmm.json +++ b/hmm.json @@ -49,7 +49,7 @@ "name": "funkin.vis", "type": "git", "dir": null, - "ref": "c6a1e24d48646849ea63563ca45561512c953779", + "ref": "38261833590773cb1de34ac5d11e0825696fc340", "url": "https://github.com/FunkinCrew/funkVis" }, { From 004ed32fad81f096a925b3e3068e55e27fd33a3d Mon Sep 17 00:00:00 2001 From: Axuko Date: Mon, 27 May 2024 22:34:28 -0700 Subject: [PATCH 033/131] Remove alot of unused imoprts --- source/funkin/api/newgrounds/NGUnsafe.hx | 4 ---- source/funkin/api/newgrounds/NGio.hx | 8 -------- source/funkin/audio/FunkinSound.hx | 3 +-- source/funkin/audio/VoicesGroup.hx | 2 -- source/funkin/audio/visualize/ABotVis.hx | 4 ---- source/funkin/audio/visualize/PolygonVisGroup.hx | 1 - source/funkin/audio/visualize/SpectogramSprite.hx | 12 ------------ source/funkin/audio/visualize/VisShit.hx | 5 ----- source/funkin/audio/visualize/dsp/FFT.hx | 2 -- source/funkin/audio/waveform/WaveformData.hx | 2 -- source/funkin/audio/waveform/WaveformSprite.hx | 2 -- .../data/dialogue/conversation/ConversationData.hx | 2 -- .../dialogue/conversation/ConversationRegistry.hx | 1 - 13 files changed, 1 insertion(+), 47 deletions(-) diff --git a/source/funkin/api/newgrounds/NGUnsafe.hx b/source/funkin/api/newgrounds/NGUnsafe.hx index 9616dfe1..77e44bd1 100644 --- a/source/funkin/api/newgrounds/NGUnsafe.hx +++ b/source/funkin/api/newgrounds/NGUnsafe.hx @@ -1,9 +1,5 @@ package funkin.api.newgrounds; -import flixel.util.FlxSignal; -import flixel.util.FlxTimer; -import lime.app.Application; -import openfl.display.Stage; #if newgrounds import io.newgrounds.NG; import io.newgrounds.NGLite; diff --git a/source/funkin/api/newgrounds/NGio.hx b/source/funkin/api/newgrounds/NGio.hx index c1f8ad3b..3f5fc078 100644 --- a/source/funkin/api/newgrounds/NGio.hx +++ b/source/funkin/api/newgrounds/NGio.hx @@ -2,19 +2,11 @@ package funkin.api.newgrounds; #if newgrounds import flixel.util.FlxSignal; -import flixel.util.FlxTimer; import io.newgrounds.NG; import io.newgrounds.NGLite; -import io.newgrounds.components.ScoreBoardComponent.Period; import io.newgrounds.objects.Error; -import io.newgrounds.objects.Medal; import io.newgrounds.objects.Score; -import io.newgrounds.objects.ScoreBoard; -import io.newgrounds.objects.events.Response; -import io.newgrounds.objects.events.Result.GetCurrentVersionResult; -import io.newgrounds.objects.events.Result.GetVersionResult; import lime.app.Application; -import openfl.display.Stage; #end /** diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index df05cc3e..939b17f2 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -11,10 +11,9 @@ import funkin.audio.waveform.WaveformDataParser; import funkin.data.song.SongData.SongMusicData; import funkin.data.song.SongRegistry; import funkin.util.tools.ICloneable; -import openfl.Assets; import openfl.media.SoundMixer; + #if (openfl >= "8.0.0") -import openfl.utils.AssetType; #end /** diff --git a/source/funkin/audio/VoicesGroup.hx b/source/funkin/audio/VoicesGroup.hx index 5037ee1d..9a1e0e0c 100644 --- a/source/funkin/audio/VoicesGroup.hx +++ b/source/funkin/audio/VoicesGroup.hx @@ -1,9 +1,7 @@ package funkin.audio; -import funkin.audio.FunkinSound; import flixel.group.FlxGroup.FlxTypedGroup; import funkin.audio.waveform.WaveformData; -import funkin.audio.waveform.WaveformDataParser; class VoicesGroup extends SoundGroup { diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index ca77dd58..b94f20b3 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -1,13 +1,9 @@ package funkin.audio.visualize; -import funkin.audio.visualize.dsp.FFT; import flixel.FlxSprite; -import flixel.addons.plugin.taskManager.FlxTask; import flixel.graphics.frames.FlxAtlasFrames; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; -import flixel.math.FlxMath; import flixel.sound.FlxSound; -import funkin.util.MathUtil; import funkin.vis.dsp.SpectralAnalyzer; import funkin.vis.audioclip.frontends.LimeAudioClip; diff --git a/source/funkin/audio/visualize/PolygonVisGroup.hx b/source/funkin/audio/visualize/PolygonVisGroup.hx index cc68f4ae..bff84579 100644 --- a/source/funkin/audio/visualize/PolygonVisGroup.hx +++ b/source/funkin/audio/visualize/PolygonVisGroup.hx @@ -1,6 +1,5 @@ package funkin.audio.visualize; -import funkin.audio.visualize.PolygonSpectogram; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.sound.FlxSound; diff --git a/source/funkin/audio/visualize/SpectogramSprite.hx b/source/funkin/audio/visualize/SpectogramSprite.hx index 636c0726..615e80d9 100644 --- a/source/funkin/audio/visualize/SpectogramSprite.hx +++ b/source/funkin/audio/visualize/SpectogramSprite.hx @@ -8,8 +8,6 @@ import flixel.sound.FlxSound; import flixel.util.FlxColor; import funkin.audio.visualize.PolygonSpectogram.VISTYPE; import funkin.audio.visualize.VisShit.CurAudioInfo; -import funkin.audio.visualize.dsp.FFT; -import lime.system.ThreadPool; import lime.utils.Int16Array; using Lambda; @@ -38,8 +36,6 @@ class SpectogramSprite extends FlxTypedSpriteGroup lengthOfShit = amnt; regenLineShit(); - - // makeGraphic(200, 200, FlxColor.BLACK); } public function regenLineShit():Void @@ -89,8 +85,6 @@ class SpectogramSprite extends FlxTypedSpriteGroup { checkAndSetBuffer(); - // vis.checkAndSetBuffer(); - if (setBuffer) { var samplesToGen:Int = Std.int(sampleRate * seconds); @@ -191,7 +185,6 @@ class SpectogramSprite extends FlxTypedSpriteGroup // a value between 10hz and 100Khz var hzPicker:Float = Math.pow(10, powedShit); - // var sampleApprox:Int = Std.int(FlxMath.remapToRange(i, 0, group.members.length, startingSample, startingSample + samplesToGen)); var remappedFreq:Int = Std.int(FlxMath.remapToRange(hzPicker, 0, 10000, 0, freqShit[0].length - 1)); group.members[i].x = prevLine.x; @@ -211,8 +204,6 @@ class SpectogramSprite extends FlxTypedSpriteGroup var line = FlxPoint.get(prevLine.x - group.members[i].x, prevLine.y - group.members[i].y); // dont draw a line until i figure out a nicer way to view da spikes and shit idk lol! - // group.members[i].setGraphicSize(Std.int(Math.max(line.length, 1)), Std.int(1)); - // group.members[i].angle = line.degrees; } } } @@ -261,9 +252,6 @@ class SpectogramSprite extends FlxTypedSpriteGroup group.members[Std.int(remappedSample)].x = prevLine.x; group.members[Std.int(remappedSample)].y = prevLine.y; - // group.members[0].y = prevLine.y; - - // FlxSpriteUtil.drawLine(this, prevLine.x, prevLine.y, width * remappedSample, left * height / 2 + height / 2); prevLine.x = (curAud.balanced * swagheight / 2 + swagheight / 2) + x; prevLine.y = (Std.int(remappedSample) / lengthOfShit * daHeight) + y; diff --git a/source/funkin/audio/visualize/VisShit.hx b/source/funkin/audio/visualize/VisShit.hx index 204ced1e..ba235fe8 100644 --- a/source/funkin/audio/visualize/VisShit.hx +++ b/source/funkin/audio/visualize/VisShit.hx @@ -3,7 +3,6 @@ package funkin.audio.visualize; import flixel.math.FlxMath; import flixel.sound.FlxSound; import funkin.audio.visualize.dsp.FFT; -import lime.system.ThreadPool; import lime.utils.Int16Array; import funkin.util.MathUtil; @@ -73,9 +72,6 @@ class VisShit freqOutput.push([]); - // if (FlxG.keys.justPressed.M) - // trace(FFT.rfft(chunk).map(z -> z.scale(1 / fs).magnitude)); - // find spectral peaks and their instantaneous frequencies for (k => s in freqs) { @@ -91,7 +87,6 @@ class VisShit if (freq < maxFreq) freqOutput[indexOfArray].push(power); // } - // haxe.Log.trace("", null); indexOfArray++; // move to next (overlapping) chunk diff --git a/source/funkin/audio/visualize/dsp/FFT.hx b/source/funkin/audio/visualize/dsp/FFT.hx index dc75acb8..40ee9cb8 100644 --- a/source/funkin/audio/visualize/dsp/FFT.hx +++ b/source/funkin/audio/visualize/dsp/FFT.hx @@ -1,7 +1,5 @@ package funkin.audio.visualize.dsp; -import funkin.audio.visualize.dsp.Complex; - using funkin.audio.visualize.dsp.OffsetArray; using funkin.audio.visualize.dsp.Signal; diff --git a/source/funkin/audio/waveform/WaveformData.hx b/source/funkin/audio/waveform/WaveformData.hx index 1f649b47..a939f91b 100644 --- a/source/funkin/audio/waveform/WaveformData.hx +++ b/source/funkin/audio/waveform/WaveformData.hx @@ -1,7 +1,5 @@ package funkin.audio.waveform; -import funkin.util.MathUtil; - @:nullSafety class WaveformData { diff --git a/source/funkin/audio/waveform/WaveformSprite.hx b/source/funkin/audio/waveform/WaveformSprite.hx index 32ced2fb..8eaba811 100644 --- a/source/funkin/audio/waveform/WaveformSprite.hx +++ b/source/funkin/audio/waveform/WaveformSprite.hx @@ -1,7 +1,5 @@ package funkin.audio.waveform; -import funkin.audio.waveform.WaveformData; -import funkin.audio.waveform.WaveformDataParser; import funkin.graphics.rendering.MeshRender; import flixel.util.FlxColor; diff --git a/source/funkin/data/dialogue/conversation/ConversationData.hx b/source/funkin/data/dialogue/conversation/ConversationData.hx index 30e3f451..65051983 100644 --- a/source/funkin/data/dialogue/conversation/ConversationData.hx +++ b/source/funkin/data/dialogue/conversation/ConversationData.hx @@ -1,7 +1,5 @@ package funkin.data.dialogue.conversation; -import funkin.data.animation.AnimationData; - /** * A type definition for the data for a specific conversation. * It includes things like what dialogue boxes to use, what text to display, and what animations to play. diff --git a/source/funkin/data/dialogue/conversation/ConversationRegistry.hx b/source/funkin/data/dialogue/conversation/ConversationRegistry.hx index ca072897..fad1e43a 100644 --- a/source/funkin/data/dialogue/conversation/ConversationRegistry.hx +++ b/source/funkin/data/dialogue/conversation/ConversationRegistry.hx @@ -1,7 +1,6 @@ package funkin.data.dialogue.conversation; import funkin.play.cutscene.dialogue.Conversation; -import funkin.data.dialogue.conversation.ConversationData; import funkin.play.cutscene.dialogue.ScriptedConversation; class ConversationRegistry extends BaseRegistry From 9a47666fc7f5e51dc3b58df2023ec63d6a61202f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 28 May 2024 01:37:30 -0400 Subject: [PATCH 034/131] Fix a merge issue. --- source/funkin/input/Controls.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx index 31551dec..345791ee 100644 --- a/source/funkin/input/Controls.hx +++ b/source/funkin/input/Controls.hx @@ -997,7 +997,7 @@ class Controls extends FlxActionSet for (control in Control.createAll()) { var inputs:Array = Reflect.field(data, control.getName()); - inputs = inputs.unique(); + inputs = inputs.distinct(); if (inputs != null) { if (inputs.length == 0) { @@ -1050,7 +1050,7 @@ class Controls extends FlxActionSet if (inputs.length == 0) { inputs = [FlxKey.NONE]; } else { - inputs = inputs.unique(); + inputs = inputs.distinct(); } Reflect.setField(data, control.getName(), inputs); From d4b2e9496382ef967d425d7fe92ca4a816dafe04 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 28 May 2024 02:17:55 -0400 Subject: [PATCH 035/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 8a8239cb..371cce1f 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8a8239cb50b5277fb0cfce041b3d8a9dfc780c35 +Subproject commit 371cce1fdc44914ddc3a5327e996cece4e676715 From 1ae30283a3a0d2a3bafb6d4da84d906764e80ed6 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 28 May 2024 15:34:09 -0400 Subject: [PATCH 036/131] re add the xmlns schema stuff --- Project.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Project.xml b/Project.xml index 24cdac27..dce45546 100644 --- a/Project.xml +++ b/Project.xml @@ -1,5 +1,6 @@ - + @@ -14,6 +15,7 @@ + < @@ -28,7 +30,7 @@ - + From 01b6a11ddbbacc034f73b61451b78587b3536b7d Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 28 May 2024 22:57:01 -0400 Subject: [PATCH 037/131] flxpartialsound lock to current version --- hmm.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hmm.json b/hmm.json index 6b119c52..5260d522 100644 --- a/hmm.json +++ b/hmm.json @@ -4,7 +4,7 @@ "name": "FlxPartialSound", "type": "git", "dir": null, - "ref": "main", + "ref": "8bb8ed50f520d9cd64a65414b119b8718924b93a", "url": "https://github.com/FunkinCrew/FlxPartialSound.git" }, { @@ -178,4 +178,4 @@ "url": "https://github.com/FunkinCrew/thx.semver" } ] -} \ No newline at end of file +} From 2d300039ae42988c570af0f36225c1732a4fb09c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 28 May 2024 23:53:50 -0400 Subject: [PATCH 038/131] promises + error out partial sounds that attempt to load multiple times --- source/funkin/audio/FunkinSound.hx | 32 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index aaddda9d..39a26aac 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -360,24 +360,24 @@ class FunkinSound extends FlxSound implements ICloneable if (shouldLoadPartial) { var music = FunkinSound.loadPartial(pathToUse, params.partialParams?.start ?? 0, params.partialParams?.end ?? 1, params?.startingVolume ?? 1.0, - params.loop ?? true, false, true, params.onComplete, params.onLoad); + params.loop ?? true, false, false, params.onComplete); if (music != null) { - for (future in partialQueue) + while (partialQueue.length > 0) { - future = cast Future.withError("Music was overridden by another partial load"); + @:nullSafety(Off) + partialQueue.pop().error("Cancel loading partial sound"); } - partialQueue = []; + partialQueue.push(music); @:nullSafety(Off) - music.onComplete(function(partialMusic:Null) { - if (partialQueue.pop() == music) - { - FlxG.sound.music = partialMusic; - FlxG.sound.list.remove(FlxG.sound.music); - } + music.future.onComplete(function(partialMusic:Null) { + FlxG.sound.music = partialMusic; + FlxG.sound.list.remove(FlxG.sound.music); + + if (params.onLoad != null) params.onLoad(); }); return true; @@ -406,7 +406,7 @@ class FunkinSound extends FlxSound implements ICloneable } } - static var partialQueue:Array>> = []; + static var partialQueue:Array>> = []; /** * Creates a new `FunkinSound` object synchronously. @@ -478,7 +478,7 @@ class FunkinSound extends FlxSound implements ICloneable * @return A FunkinSound object */ public static function loadPartial(path:String, start:Float = 0, end:Float = 1, volume:Float = 1.0, looped:Bool = false, autoDestroy:Bool = false, - autoPlay:Bool = true, ?onComplete:Void->Void, ?onLoad:Void->Void):Future> + autoPlay:Bool = true, ?onComplete:Void->Void, ?onLoad:Void->Void):Promise> { var promise:lime.app.Promise> = new lime.app.Promise>(); @@ -488,12 +488,16 @@ class FunkinSound extends FlxSound implements ICloneable var soundRequest = FlxPartialSound.partialLoadFromFile(path, start, end); - soundRequest.onComplete(function(partialSound) { + promise.future.onError(function(e) { + soundRequest.error("Sound loading was errored or cancelled"); + }); + + soundRequest.future.onComplete(function(partialSound) { var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad); promise.complete(snd); }); - return promise.future; + return promise; } @:nullSafety(Off) From 1f64c7fcc9757004925fdb641f5b9f19be248e5f Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 28 May 2024 23:54:23 -0400 Subject: [PATCH 039/131] update hmm flxpartialsound --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 5260d522..91d2f08b 100644 --- a/hmm.json +++ b/hmm.json @@ -4,7 +4,7 @@ "name": "FlxPartialSound", "type": "git", "dir": null, - "ref": "8bb8ed50f520d9cd64a65414b119b8718924b93a", + "ref": "44aa7eb", "url": "https://github.com/FunkinCrew/FlxPartialSound.git" }, { From d97d77566e1e30800bb3c5f8ba973af38a8ded0b Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 29 May 2024 00:53:32 -0400 Subject: [PATCH 040/131] Make song score lerp faster --- source/funkin/ui/story/StoryMenuState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index 820ac2ad..c1a001e5 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -306,7 +306,7 @@ class StoryMenuState extends MusicBeatState { Conductor.instance.update(); - highScoreLerp = Std.int(MathUtil.smoothLerp(highScoreLerp, highScore, elapsed, 0.5)); + highScoreLerp = Std.int(MathUtil.smoothLerp(highScoreLerp, highScore, elapsed, 0.25)); scoreText.text = 'LEVEL SCORE: ${Math.round(highScoreLerp)}'; From fb752ddd7860248c208fc612a4630f4be2bcee1c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 29 May 2024 17:05:20 -0400 Subject: [PATCH 041/131] remove random < in project.xml lol --- Project.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/Project.xml b/Project.xml index 16e4b985..fcd29a25 100644 --- a/Project.xml +++ b/Project.xml @@ -15,7 +15,6 @@ xsi:schemaLocation="http://lime.openfl.org/project/1.0.4 http://lime.openfl.org/ - < From 8d7591a796f9c0c392eb66c8e494d5f9a7a5e36a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 29 May 2024 21:43:54 -0400 Subject: [PATCH 042/131] Fix an issue where Story Menu props wouldn't render. --- source/funkin/ui/story/LevelProp.hx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/funkin/ui/story/LevelProp.hx b/source/funkin/ui/story/LevelProp.hx index 5a3efc36..0547404a 100644 --- a/source/funkin/ui/story/LevelProp.hx +++ b/source/funkin/ui/story/LevelProp.hx @@ -11,12 +11,15 @@ class LevelProp extends Bopper function set_propData(value:LevelPropData):LevelPropData { // Only reset the prop if the asset path has changed. - if (propData == null || value?.assetPath != propData?.assetPath) + if (propData == null || !(thx.Dynamics.equals(value, propData))) { + this.propData = value; + + this.visible = this.propData != null; + danceEvery = this.propData?.danceEvery ?? 0; + applyData(); } - this.visible = (value != null); - danceEvery = this.propData?.danceEvery ?? 0; return this.propData; } From 174c595837a63fef473ad191576e51862c240cc0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 29 May 2024 22:49:57 -0400 Subject: [PATCH 043/131] Fix crash caused by improperly canceling a tween --- source/funkin/play/PauseSubState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index c345871a..8c45fac6 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -234,7 +234,7 @@ class PauseSubState extends MusicBeatSubState public override function destroy():Void { super.destroy(); - charterFadeTween.destroy(); + charterFadeTween.cancel(); charterFadeTween = null; pauseMusic.stop(); } From 6572d13a7f3212a047b2cb2266edf6938ddd7e2f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 29 May 2024 23:21:32 -0400 Subject: [PATCH 044/131] Improve documentation a bit. --- source/funkin/play/event/ScrollSpeedEvent.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/funkin/play/event/ScrollSpeedEvent.hx b/source/funkin/play/event/ScrollSpeedEvent.hx index 9abd4be9..c752d2f6 100644 --- a/source/funkin/play/event/ScrollSpeedEvent.hx +++ b/source/funkin/play/event/ScrollSpeedEvent.hx @@ -21,7 +21,9 @@ import funkin.data.event.SongEventSchema.SongEventFieldType; * "v": { * "scroll": "1.3", * "duration": "4", - * "ease": "linear" + * "ease": "linear", + * "strumline": "both", + * "absolute": false * } * } * ``` @@ -98,6 +100,8 @@ class ScrollSpeedEvent extends SongEvent * 'scroll': FLOAT, // Target scroll level. * 'duration': FLOAT, // Duration in steps. * 'ease': ENUM, // Easing function. + * 'strumline': ENUM, // Which strumline to change + * 'absolute': BOOL, // True to set the scroll speed to the target level, false to set the scroll speed to (target level x base scroll speed) * } * @return SongEventSchema */ From 68e9937b43994f7fb1b21347bad3cd02ef195815 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Thu, 30 May 2024 04:33:26 +0100 Subject: [PATCH 045/131] interval shake class --- source/funkin/effects/IntervalShake.hx | 240 +++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 source/funkin/effects/IntervalShake.hx diff --git a/source/funkin/effects/IntervalShake.hx b/source/funkin/effects/IntervalShake.hx new file mode 100644 index 00000000..545739cc --- /dev/null +++ b/source/funkin/effects/IntervalShake.hx @@ -0,0 +1,240 @@ +package funkin.effects; + +import flixel.FlxObject; +import flixel.util.FlxDestroyUtil.IFlxDestroyable; +import flixel.util.FlxPool; +import flixel.util.FlxTimer; +import flixel.math.FlxPoint; +import flixel.util.FlxAxes; +import flixel.tweens.FlxEase.EaseFunction; +import flixel.math.FlxMath; + +/** + * pretty much a copy of FlxFlicker geared towards making sprites + * shake around at a set interval and slow down over time. + */ +class IntervalShake implements IFlxDestroyable +{ + static var _pool:FlxPool = new FlxPool(IntervalShake.new); + + /** + * Internal map for looking up which objects are currently shaking and getting their shake data. + */ + static var _boundObjects:Map = new Map(); + + /** + * An effect that shakes the sprite on a set interval and a starting intensity that goes down over time. + * + * @param Object The object to shake. + * @param Duration How long to shake for (in seconds). `0` means "forever". + * @param Interval In what interval to update the shake position. Set to `FlxG.elapsed` if `<= 0`! + * @param StartIntensity The starting intensity of the shake. + * @param EndIntensity The ending intensity of the shake. + * @param Ease Control the easing of the intensity over the shake. + * @param CompletionCallback Callback on shake completion + * @param ProgressCallback Callback on each shake interval + * @return The `IntervalShake` object. `IntervalShake`s are pooled internally, so beware of storing references. + */ + public static function shake(Object:FlxObject, Duration:Float = 1, Interval:Float = 0.04, StartIntensity:Float = 0, EndIntensity:Float = 0, + Ease:EaseFunction, ?CompletionCallback:IntervalShake->Void, ?ProgressCallback:IntervalShake->Void):IntervalShake + { + if (isShaking(Object)) + { + // if (ForceRestart) + // { + // stopShaking(Object); + // } + // else + // { + // Ignore this call if object is already flickering. + return _boundObjects[Object]; + // } + } + + if (Interval <= 0) + { + Interval = FlxG.elapsed; + } + + var shake:IntervalShake = _pool.get(); + shake.start(Object, Duration, Interval, StartIntensity, EndIntensity, Ease, CompletionCallback, ProgressCallback); + return _boundObjects[Object] = shake; + } + + /** + * Returns whether the object is shaking or not. + * + * @param Object The object to test. + */ + public static function isShaking(Object:FlxObject):Bool + { + return _boundObjects.exists(Object); + } + + /** + * Stops shaking the object. + * + * @param Object The object to stop shaking. + */ + public static function stopShaking(Object:FlxObject):Void + { + var boundShake:IntervalShake = _boundObjects[Object]; + if (boundShake != null) + { + boundShake.stop(); + } + } + + /** + * The shaking object. + */ + public var object(default, null):FlxObject; + + /** + * The shaking timer. You can check how many seconds has passed since shaking started etc. + */ + public var timer(default, null):FlxTimer; + + /** + * The starting intensity of the shake. + */ + public var startIntensity(default, null):Float; + + /** + * The ending intensity of the shake. + */ + public var endIntensity(default, null):Float; + + /** + * How long to shake for (in seconds). `0` means "forever". + */ + public var duration(default, null):Float; + + /** + * The interval of the shake. + */ + public var interval(default, null):Float; + + /** + * Defines on what axes to `shake()`. Default value is `XY` / both. + */ + public var axes(default, null):FlxAxes; + + /** + * Defines the initial position of the object at the beginning of the shake effect. + */ + public var initialOffset(default, null):FlxPoint; + + /** + * The callback that will be triggered after the shake has completed. + */ + public var completionCallback(default, null):IntervalShake->Void; + + /** + * The callback that will be triggered every time the object shakes. + */ + public var progressCallback(default, null):IntervalShake->Void; + + /** + * The easing of the intensity over the shake. + */ + public var ease(default, null):EaseFunction; + + /** + * Nullifies the references to prepare object for reuse and avoid memory leaks. + */ + public function destroy():Void + { + object = null; + timer = null; + ease = null; + completionCallback = null; + progressCallback = null; + } + + /** + * Starts shaking behavior. + */ + function start(Object:FlxObject, Duration:Float = 1, Interval:Float = 0.04, StartIntensity:Float = 0, EndIntensity:Float = 0, Ease:EaseFunction, + ?CompletionCallback:IntervalShake->Void, ?ProgressCallback:IntervalShake->Void):Void + { + object = Object; + duration = Duration; + interval = Interval; + completionCallback = CompletionCallback; + startIntensity = StartIntensity; + endIntensity = EndIntensity; + initialOffset = new FlxPoint(Object.x, Object.y); + ease = Ease; + axes = FlxAxes.XY; + _secondsSinceStart = 0; + timer = new FlxTimer().start(interval, shakeProgress, Std.int(duration / interval)); + } + + /** + * Prematurely ends shaking. + */ + public function stop():Void + { + timer.cancel(); + // object.visible = true; + object.x = initialOffset.x; + object.y = initialOffset.y; + release(); + } + + /** + * Unbinds the object from shaking and releases it into pool for reuse. + */ + function release():Void + { + _boundObjects.remove(object); + _pool.put(this); + } + + public var _secondsSinceStart(default, null):Float = 0; + + public var scale(default, null):Float = 0; + + /** + * Just a helper function for shake() to update object's position. + */ + function shakeProgress(timer:FlxTimer):Void + { + _secondsSinceStart += interval; + scale = _secondsSinceStart / duration; + if (ease != null) + { + scale = 1 - ease(scale); + // trace(scale); + } + + var curIntensity:Float = 0; + curIntensity = FlxMath.lerp(endIntensity, startIntensity, scale); + + if (axes.x) object.x = initialOffset.x + FlxG.random.float((-curIntensity) * object.width, (curIntensity) * object.width); + if (axes.y) object.y = initialOffset.y + FlxG.random.float((-curIntensity) * object.width, (curIntensity) * object.width); + + // object.visible = !object.visible; + + if (progressCallback != null) progressCallback(this); + + if (timer.loops > 0 && timer.loopsLeft == 0) + { + object.x = initialOffset.x; + object.y = initialOffset.y; + if (completionCallback != null) + { + completionCallback(this); + } + + if (this.timer == timer) release(); + } + } + + /** + * Internal constructor. Use static methods. + */ + @:keep + function new() {} +} From e7079452fb4e54cc26d8c1cd132d70d0103a5d37 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Thu, 30 May 2024 04:34:00 +0100 Subject: [PATCH 046/131] freeplay visual changes + base rank visuals --- source/funkin/ui/freeplay/CapsuleText.hx | 135 +++++++ source/funkin/ui/freeplay/DJBoyfriend.hx | 35 ++ source/funkin/ui/freeplay/FreeplayState.hx | 396 +++++++++++++++++- source/funkin/ui/freeplay/SongMenuItem.hx | 450 ++++++++++++++++++++- 4 files changed, 992 insertions(+), 24 deletions(-) diff --git a/source/funkin/ui/freeplay/CapsuleText.hx b/source/funkin/ui/freeplay/CapsuleText.hx index 3a520e01..c3fd51d1 100644 --- a/source/funkin/ui/freeplay/CapsuleText.hx +++ b/source/funkin/ui/freeplay/CapsuleText.hx @@ -4,6 +4,12 @@ import openfl.filters.BitmapFilterQuality; import flixel.text.FlxText; import flixel.group.FlxSpriteGroup; import funkin.graphics.shaders.GaussianBlurShader; +import funkin.graphics.shaders.LeftMaskShader; +import flixel.math.FlxRect; +import flixel.tweens.FlxEase; +import flixel.util.FlxTimer; +import flixel.tweens.FlxTween; +import openfl.display.BlendMode; class CapsuleText extends FlxSpriteGroup { @@ -13,6 +19,15 @@ class CapsuleText extends FlxSpriteGroup public var text(default, set):String; + var maskShaderSongName:LeftMaskShader = new LeftMaskShader(); + + public var clipWidth(default, set):Int = 255; + + public var tooLong:Bool = false; + + // 255, 27 normal + // 220, 27 favourited + public function new(x:Float, y:Float, songTitle:String, size:Float) { super(x, y); @@ -36,6 +51,30 @@ class CapsuleText extends FlxSpriteGroup return text; } + // ???? none + // 255, 27 normal + // 220, 27 favourited + + function set_clipWidth(value:Int):Int + { + resetText(); + if (whiteText.width > value) + { + tooLong = true; + + blurredText.clipRect = new FlxRect(0, 0, value, blurredText.height); + whiteText.clipRect = new FlxRect(0, 0, value, whiteText.height); + } + else + { + tooLong = false; + + blurredText.clipRect = null; + whiteText.clipRect = null; + } + return clipWidth = value; + } + function set_text(value:String):String { if (value == null) return value; @@ -51,6 +90,102 @@ class CapsuleText extends FlxSpriteGroup new openfl.filters.GlowFilter(0x00ccff, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM), // new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW) ]; + return text = value; } + + var moveTimer:FlxTimer = new FlxTimer(); + var moveTween:FlxTween; + + public function initMove():Void + { + moveTimer.start(0.6, (timer) -> { + moveTextRight(); + }); + } + + function moveTextRight():Void + { + var distToMove:Float = whiteText.width - clipWidth; + moveTween = FlxTween.tween(whiteText.offset, {x: distToMove}, 2, + { + onUpdate: function(_) { + whiteText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + blurredText.offset = whiteText.offset; + blurredText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, blurredText.height); + }, + onComplete: function(_) { + moveTimer.start(0.3, (timer) -> { + moveTextLeft(); + }); + }, + ease: FlxEase.sineInOut + }); + } + + function moveTextLeft():Void + { + moveTween = FlxTween.tween(whiteText.offset, {x: 0}, 2, + { + onUpdate: function(_) { + whiteText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + blurredText.offset = whiteText.offset; + blurredText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, blurredText.height); + }, + onComplete: function(_) { + moveTimer.start(0.3, (timer) -> { + moveTextRight(); + }); + }, + ease: FlxEase.sineInOut + }); + } + + public function resetText():Void + { + if (moveTween != null) moveTween.cancel(); + if (moveTimer != null) moveTimer.cancel(); + whiteText.offset.x = 0; + whiteText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + blurredText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + } + + var flickerState:Bool = false; + var flickerTimer:FlxTimer; + + public function flickerText():Void + { + resetText(); + flickerTimer = new FlxTimer().start(1 / 24, flickerProgress, 19); + } + + function flickerProgress(timer:FlxTimer):Void + { + if (flickerState == true) + { + whiteText.blend = BlendMode.ADD; + blurredText.blend = BlendMode.ADD; + blurredText.color = 0xFFFFFFFF; + whiteText.color = 0xFFFFFFFF; + whiteText.textField.filters = [ + new openfl.filters.GlowFilter(0xFFFFFF, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM), + // new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW) + ]; + } + else + { + blurredText.color = 0xFF00aadd; + whiteText.color = 0xFFDDDDDD; + whiteText.textField.filters = [ + new openfl.filters.GlowFilter(0xDDDDDD, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM), + // new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW) + ]; + } + flickerState = !flickerState; + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + } } diff --git a/source/funkin/ui/freeplay/DJBoyfriend.hx b/source/funkin/ui/freeplay/DJBoyfriend.hx index 5f1144fa..248526aa 100644 --- a/source/funkin/ui/freeplay/DJBoyfriend.hx +++ b/source/funkin/ui/freeplay/DJBoyfriend.hx @@ -82,6 +82,8 @@ class DJBoyfriend extends FlxAtlasSprite return anims; } + var lowPumpLoopPoint:Int = 4; + public override function update(elapsed:Float):Void { super.update(elapsed); @@ -114,6 +116,14 @@ class DJBoyfriend extends FlxAtlasSprite case Confirm: if (getCurrentAnimation() != 'Boyfriend DJ confirm') playFlashAnimation('Boyfriend DJ confirm', false); timeSinceSpook = 0; + case PumpIntro: + if (getCurrentAnimation() != 'Boyfriend DJ fist pump') playFlashAnimation('Boyfriend DJ fist pump', false); + if (getCurrentAnimation() == 'Boyfriend DJ fist pump' && anim.curFrame >= 4) + { + anim.play("Boyfriend DJ fist pump", true, false, 0); + } + case FistPump: + case Spook: if (getCurrentAnimation() != 'bf dj afk') { @@ -174,6 +184,12 @@ class DJBoyfriend extends FlxAtlasSprite currentState = Idle; case "Boyfriend DJ confirm": + case "Boyfriend DJ fist pump": + currentState = Idle; + + case "Boyfriend DJ loss reaction 1": + currentState = Idle; + case "Boyfriend DJ watchin tv OG": var frame:Int = FlxG.random.bool(33) ? 112 : 166; @@ -275,6 +291,23 @@ class DJBoyfriend extends FlxAtlasSprite currentState = Confirm; } + public function fistPump():Void + { + currentState = PumpIntro; + } + + public function pumpFist():Void + { + currentState = FistPump; + anim.play("Boyfriend DJ fist pump", true, false, 4); + } + + public function pumpFistBad():Void + { + currentState = FistPump; + anim.play("Boyfriend DJ loss reaction 1", true, false, 4); + } + public inline function addOffset(name:String, x:Float = 0, y:Float = 0) { animOffsets[name] = [x, y]; @@ -331,6 +364,8 @@ enum DJBoyfriendState Intro; Idle; Confirm; + PumpIntro; + FistPump; Spook; TV; } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 7b754384..a665f075 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1,5 +1,6 @@ package funkin.ui.freeplay; +import funkin.graphics.adobeanimate.FlxAtlasSprite; import flixel.addons.transition.FlxTransitionableState; import flixel.addons.ui.FlxInputText; import flixel.FlxCamera; @@ -10,6 +11,7 @@ import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.input.touch.FlxTouch; import flixel.math.FlxAngle; import flixel.math.FlxPoint; +import openfl.display.BlendMode; import flixel.system.debug.watch.Tracker.TrackerProfile; import flixel.text.FlxText; import flixel.tweens.FlxEase; @@ -38,6 +40,8 @@ import funkin.ui.transition.LoadingState; import funkin.ui.transition.StickerSubState; import funkin.util.MathUtil; import lime.utils.Assets; +import flixel.tweens.misc.ShakeTween; +import funkin.effects.IntervalShake; /** * Parameters used to initialize the FreeplayState. @@ -135,6 +139,29 @@ class FreeplayState extends MusicBeatSubState public static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; public static var rememberedSongId:Null = 'tutorial'; + var funnyCam:FunkinCamera; + var rankCamera:FunkinCamera; + var rankBg:FunkinSprite; + var rankVignette:FlxSprite; + + var backingTextYeah:FlxAtlasSprite; + var orangeBackShit:FunkinSprite; + var alsoOrangeLOL:FunkinSprite; + var pinkBack:FunkinSprite; + var confirmGlow:FlxSprite; + var confirmGlow2:FlxSprite; + var confirmTextGlow:FlxSprite; + + var moreWays:BGScrollingText; + var funnyScroll:BGScrollingText; + var txtNuts:BGScrollingText; + var funnyScroll2:BGScrollingText; + var moreWays2:BGScrollingText; + var funnyScroll3:BGScrollingText; + + var bgDad:FlxSprite; + var cardGlow:FlxSprite; + public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { currentCharacter = params?.character ?? Constants.DEFAULT_CHARACTER; @@ -216,17 +243,17 @@ class FreeplayState extends MusicBeatSubState trace(FlxG.camera.initialZoom); trace(FlxCamera.defaultZoom); - var pinkBack:FunkinSprite = FunkinSprite.create('freeplay/pinkBack'); + pinkBack = FunkinSprite.create('freeplay/pinkBack'); pinkBack.color = 0xFFFFD4E9; // sets it to pink! pinkBack.x -= pinkBack.width; FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut}); add(pinkBack); - var orangeBackShit:FunkinSprite = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFFEDA00); + orangeBackShit = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFFEDA00); add(orangeBackShit); - var alsoOrangeLOL:FunkinSprite = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFFFD400); + alsoOrangeLOL = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFFFD400); add(alsoOrangeLOL); exitMovers.set([pinkBack, orangeBackShit, alsoOrangeLOL], @@ -241,13 +268,30 @@ class FreeplayState extends MusicBeatSubState orangeBackShit.visible = false; alsoOrangeLOL.visible = false; + confirmTextGlow = new FlxSprite(-8, 115).loadGraphic(Paths.image('freeplay/glowingText')); + confirmTextGlow.blend = BlendMode.ADD; + confirmTextGlow.visible = false; + + confirmGlow = new FlxSprite(-30, 240).loadGraphic(Paths.image('freeplay/confirmGlow')); + confirmGlow.blend = BlendMode.ADD; + + confirmGlow2 = new FlxSprite(confirmGlow.x, confirmGlow.y).loadGraphic(Paths.image('freeplay/confirmGlow2')); + + confirmGlow.visible = false; + confirmGlow2.visible = false; + + add(confirmGlow2); + add(confirmGlow); + + add(confirmTextGlow); + var grpTxtScrolls:FlxGroup = new FlxGroup(); add(grpTxtScrolls); grpTxtScrolls.visible = false; FlxG.debugger.addTrackerProfile(new TrackerProfile(BGScrollingText, ['x', 'y', 'speed', 'size'])); - var moreWays:BGScrollingText = new BGScrollingText(0, 160, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); + moreWays = new BGScrollingText(0, 160, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); moreWays.funnyColor = 0xFFFFF383; moreWays.speed = 6.8; grpTxtScrolls.add(moreWays); @@ -258,7 +302,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.4, }); - var funnyScroll:BGScrollingText = new BGScrollingText(0, 220, 'BOYFRIEND', FlxG.width / 2, false, 60); + funnyScroll = new BGScrollingText(0, 220, 'BOYFRIEND', FlxG.width / 2, false, 60); funnyScroll.funnyColor = 0xFFFF9963; funnyScroll.speed = -3.8; grpTxtScrolls.add(funnyScroll); @@ -271,7 +315,7 @@ class FreeplayState extends MusicBeatSubState wait: 0 }); - var txtNuts:BGScrollingText = new BGScrollingText(0, 285, 'PROTECT YO NUTS', FlxG.width / 2, true, 43); + txtNuts = new BGScrollingText(0, 285, 'PROTECT YO NUTS', FlxG.width / 2, true, 43); txtNuts.speed = 3.5; grpTxtScrolls.add(txtNuts); exitMovers.set([txtNuts], @@ -280,7 +324,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.4, }); - var funnyScroll2:BGScrollingText = new BGScrollingText(0, 335, 'BOYFRIEND', FlxG.width / 2, false, 60); + funnyScroll2 = new BGScrollingText(0, 335, 'BOYFRIEND', FlxG.width / 2, false, 60); funnyScroll2.funnyColor = 0xFFFF9963; funnyScroll2.speed = -3.8; grpTxtScrolls.add(funnyScroll2); @@ -291,7 +335,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.5, }); - var moreWays2:BGScrollingText = new BGScrollingText(0, 397, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); + moreWays2 = new BGScrollingText(0, 397, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); moreWays2.funnyColor = 0xFFFFF383; moreWays2.speed = 6.8; grpTxtScrolls.add(moreWays2); @@ -302,7 +346,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.4 }); - var funnyScroll3:BGScrollingText = new BGScrollingText(0, orangeBackShit.y + 10, 'BOYFRIEND', FlxG.width / 2, 60); + funnyScroll3 = new BGScrollingText(0, orangeBackShit.y + 10, 'BOYFRIEND', FlxG.width / 2, 60); funnyScroll3.funnyColor = 0xFFFEA400; funnyScroll3.speed = -3.8; grpTxtScrolls.add(funnyScroll3); @@ -313,6 +357,24 @@ class FreeplayState extends MusicBeatSubState speed: 0.3 }); + backingTextYeah = new FlxAtlasSprite(640, 370, Paths.animateAtlas("freeplay/backing-text-yeah"), + { + FrameRate: 24.0, + Reversed: false, + // ?OnComplete:Void -> Void, + ShowPivot: false, + Antialiasing: true, + ScrollFactor: new FlxPoint(1, 1), + }); + + add(backingTextYeah); + + cardGlow = new FlxSprite(-30, -30).loadGraphic(Paths.image('freeplay/cardGlow')); + cardGlow.blend = BlendMode.ADD; + cardGlow.visible = false; + + add(cardGlow); + dj = new DJBoyfriend(640, 366); exitMovers.set([dj], { @@ -325,7 +387,7 @@ class FreeplayState extends MusicBeatSubState add(dj); - var bgDad:FlxSprite = new FlxSprite(pinkBack.width * 0.75, 0).loadGraphic(Paths.image('freeplay/freeplayBGdad')); + bgDad = new FlxSprite(pinkBack.width * 0.75, 0).loadGraphic(Paths.image('freeplay/freeplayBGdad')); bgDad.setGraphicSize(0, FlxG.height); bgDad.updateHitbox(); bgDad.shader = new AngleMask(); @@ -342,10 +404,14 @@ class FreeplayState extends MusicBeatSubState }); add(bgDad); - FlxTween.tween(blackOverlayBullshitLOLXD, {x: pinkBack.width * 0.75}, 0.7, {ease: FlxEase.quintOut}); + FlxTween.tween(blackOverlayBullshitLOLXD, {x: pinkBack.width * 0.76}, 0.7, {ease: FlxEase.quintOut}); blackOverlayBullshitLOLXD.shader = bgDad.shader; + rankBg = new FunkinSprite(0, 0); + rankBg.makeSolidColor(FlxG.width, FlxG.height, 0xD3000000); + add(rankBg); + grpSongs = new FlxTypedGroup(); add(grpSongs); @@ -527,18 +593,35 @@ class FreeplayState extends MusicBeatSubState orangeBackShit.visible = true; alsoOrangeLOL.visible = true; grpTxtScrolls.visible = true; + + cardGlow.visible = true; + FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut}); }); generateSongList(null, false); // dedicated camera for the state so we don't need to fuk around with camera scrolls from the mainmenu / elsewhere - var funnyCam:FunkinCamera = new FunkinCamera('freeplayFunny', 0, 0, FlxG.width, FlxG.height); + funnyCam = new FunkinCamera('freeplayFunny', 0, 0, FlxG.width, FlxG.height); funnyCam.bgColor = FlxColor.TRANSPARENT; FlxG.cameras.add(funnyCam, false); + rankVignette = new FlxSprite(0, 0).loadGraphic(Paths.image('freeplay/rankVignette')); + rankVignette.scale.set(2, 2); + rankVignette.updateHitbox(); + rankVignette.blend = BlendMode.ADD; + // rankVignette.cameras = [rankCamera]; + add(rankVignette); + rankVignette.alpha = 0; + forEach(function(bs) { bs.cameras = [funnyCam]; }); + + rankCamera = new FunkinCamera('rankCamera', 0, 0, FlxG.width, FlxG.height); + rankCamera.bgColor = FlxColor.TRANSPARENT; + FlxG.cameras.add(rankCamera, false); + rankBg.cameras = [rankCamera]; + rankBg.alpha = 0; } var currentFilter:SongFilter = null; @@ -585,6 +668,7 @@ class FreeplayState extends MusicBeatSubState for (cap in grpCapsules.members) { + cap.songText.resetText(); cap.kill(); } @@ -602,9 +686,11 @@ class FreeplayState extends MusicBeatSubState }; randomCapsule.y = randomCapsule.intendedY(0) + 10; randomCapsule.targetPos.x = randomCapsule.x; - randomCapsule.alpha = 0.5; + randomCapsule.alpha = 0; randomCapsule.songText.visible = false; randomCapsule.favIcon.visible = false; + randomCapsule.ranking.visible = false; + randomCapsule.blurredRanking.visible = false; randomCapsule.initJumpIn(0, force); randomCapsule.hsvShader = hsvShader; grpCapsules.add(randomCapsule); @@ -627,8 +713,12 @@ class FreeplayState extends MusicBeatSubState funnyMenu.favIcon.visible = tempSongs[i].isFav; funnyMenu.hsvShader = hsvShader; + funnyMenu.newText.animation.curAnim.curFrame = 45 - ((i * 4) % 45); + funnyMenu.forcePosition(); + funnyMenu.checkClip(); + grpCapsules.add(funnyMenu); } @@ -682,6 +772,210 @@ class FreeplayState extends MusicBeatSubState return songsToFilter; } + function rankAnimStart() + { + dj.fistPump(); + // rankCamera.fade(FlxColor.BLACK, 0.5, true); + rankCamera.fade(0xFF000000, 0.5, true, null, true); + FlxG.sound.music.volume = 0; + rankBg.alpha = 1; + + originalPos.x = grpCapsules.members[curSelected].x; + originalPos.y = grpCapsules.members[curSelected].y; + + grpCapsules.members[curSelected].ranking.alpha = 0; + grpCapsules.members[curSelected].blurredRanking.alpha = 0; + + rankCamera.zoom = 1.85; + FlxTween.tween(rankCamera, {"zoom": 1.8}, 0.6, {ease: FlxEase.sineIn}); + + funnyCam.zoom = 1.15; + FlxTween.tween(funnyCam, {"zoom": 1.1}, 0.6, {ease: FlxEase.sineIn}); + + grpCapsules.members[curSelected].cameras = [rankCamera]; + grpCapsules.members[curSelected].targetPos.set((FlxG.width / 2) - (grpCapsules.members[curSelected].width / 2), + (FlxG.height / 2) - (grpCapsules.members[curSelected].height / 2)); + + new FlxTimer().start(0.5, _ -> { + grpCapsules.members[curSelected].doLerp = false; + rankDisplayNew(); + }); + } + + function rankDisplayNew() + { + grpCapsules.members[curSelected].ranking.alpha = 1; + grpCapsules.members[curSelected].blurredRanking.alpha = 1; + + grpCapsules.members[curSelected].ranking.scale.set(20, 20); + grpCapsules.members[curSelected].blurredRanking.scale.set(20, 20); + // var tempr:Int = FlxG.random.int(0, 4); + + // grpCapsules.members[curSelected].ranking.rank = tempr; + grpCapsules.members[curSelected].ranking.animation.play(grpCapsules.members[curSelected].ranking.animation.curAnim.name, true); + FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1); + + grpCapsules.members[curSelected].blurredRanking.animation.play(grpCapsules.members[curSelected].blurredRanking.animation.curAnim.name, true); + FlxTween.tween(grpCapsules.members[curSelected].blurredRanking, {"scale.x": 1, "scale.y": 1}, 0.1); + + new FlxTimer().start(0.1, _ -> { + trace(grpCapsules.members[curSelected].ranking.rank); + switch (grpCapsules.members[curSelected].tempr) + { + case 0: + FunkinSound.playOnce(Paths.sound('ranks/rankinbad')); + case 4: + FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); + case 5: + FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); + default: + FunkinSound.playOnce(Paths.sound('ranks/rankinnormal')); + } + rankCamera.zoom = 1.3; + // FlxTween.tween(rankCamera, {"zoom": 1.4}, 0.3, {ease: FlxEase.elasticOut}); + + FlxTween.tween(rankCamera, {"zoom": 1.5}, 0.3, {ease: FlxEase.backInOut}); + + grpCapsules.members[curSelected].x -= 10; + grpCapsules.members[curSelected].y -= 20; + + FlxTween.tween(funnyCam, {"zoom": 1.05}, 0.3, {ease: FlxEase.elasticOut}); + + grpCapsules.members[curSelected].capsule.angle = -3; + FlxTween.tween(grpCapsules.members[curSelected].capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + + IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0.1, 0, FlxEase.quadOut); + }); + + new FlxTimer().start(0.4, _ -> { + FlxTween.tween(funnyCam, {"zoom": 1}, 0.8, {ease: FlxEase.sineIn}); + FlxTween.tween(rankCamera, {"zoom": 1.2}, 0.8, {ease: FlxEase.backIn}); + // IntervalShake.shake(grpCapsules.members[curSelected], 0.8 + 0.5, 1 / 24, 0, 2, FlxEase.quadIn); + FlxTween.tween(grpCapsules.members[curSelected], {x: originalPos.x - 7, y: originalPos.y - 80}, 0.8 + 0.5, {ease: FlxEase.quartIn}); + }); + + new FlxTimer().start(0.6, _ -> { + rankAnimSlam(); + // IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0, 0.3, FlxEase.quartIn); + }); + } + + function rankAnimSlam() + { + // FlxTween.tween(rankCamera, {"zoom": 1.9}, 0.5, {ease: FlxEase.backOut}); + FlxTween.tween(rankBg, {alpha: 0}, 0.5, {ease: FlxEase.expoIn}); + + // FlxTween.tween(grpCapsules.members[curSelected], {angle: 5}, 0.5, {ease: FlxEase.backIn}); + + switch (grpCapsules.members[curSelected].tempr) + { + case 0: + FunkinSound.playOnce(Paths.sound('ranks/loss')); + case 1: + FunkinSound.playOnce(Paths.sound('ranks/good')); + case 2: + FunkinSound.playOnce(Paths.sound('ranks/great')); + case 3: + FunkinSound.playOnce(Paths.sound('ranks/excellent')); + case 4: + FunkinSound.playOnce(Paths.sound('ranks/perfect')); + case 5: + FunkinSound.playOnce(Paths.sound('ranks/perfect')); + default: + FunkinSound.playOnce(Paths.sound('ranks/loss')); + } + + FlxTween.tween(grpCapsules.members[curSelected], {"targetPos.x": originalPos.x, "targetPos.y": originalPos.y}, 0.5, {ease: FlxEase.expoOut}); + new FlxTimer().start(0.5, _ -> { + funnyCam.shake(0.0045, 0.35); + + if (grpCapsules.members[curSelected].tempr == 0) + { + dj.pumpFistBad(); + } + else + { + dj.pumpFist(); + } + + rankCamera.zoom = 0.8; + funnyCam.zoom = 0.8; + FlxTween.tween(rankCamera, {"zoom": 1}, 1, {ease: FlxEase.elasticOut}); + FlxTween.tween(funnyCam, {"zoom": 1}, 0.8, {ease: FlxEase.elasticOut}); + + for (index => capsule in grpCapsules.members) + { + var distFromSelected:Float = Math.abs(index - curSelected) - 1; + + if (distFromSelected < 5) + { + if (index == curSelected) + { + FlxTween.cancelTweensOf(capsule); + // capsule.targetPos.x += 50; + capsule.fadeAnim(); + + rankVignette.color = capsule.getTrailColor(); + rankVignette.alpha = 1; + FlxTween.tween(rankVignette, {alpha: 0}, 0.6, {ease: FlxEase.expoOut}); + + capsule.doLerp = false; + capsule.setPosition(originalPos.x, originalPos.y); + IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12, 0, FlxEase.quadOut, function(_) { + capsule.doLerp = true; + capsule.cameras = [funnyCam]; + }, null); + + // FlxTween.tween(capsule, {"targetPos.x": capsule.targetPos.x - 50}, 0.6, + // { + // ease: FlxEase.backInOut, + // onComplete: function(_) { + // capsule.cameras = [funnyCam]; + // } + // }); + FlxTween.tween(capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + } + if (index > curSelected) + { + // capsule.color = FlxColor.RED; + new FlxTimer().start(distFromSelected / 20, _ -> { + capsule.doLerp = false; + + capsule.capsule.angle = FlxG.random.float(-10 + (distFromSelected * 2), 10 - (distFromSelected * 2)); + FlxTween.tween(capsule.capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + + IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12 / (distFromSelected + 1), 0, FlxEase.quadOut, function(_) { + capsule.doLerp = true; + }); + }); + } + + if (index < curSelected) + { + // capsule.color = FlxColor.BLUE; + new FlxTimer().start(distFromSelected / 20, _ -> { + capsule.doLerp = false; + + capsule.capsule.angle = FlxG.random.float(-10 + (distFromSelected * 2), 10 - (distFromSelected * 2)); + FlxTween.tween(capsule.capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + + IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12 / (distFromSelected + 1), 0, FlxEase.quadOut, function(_) { + capsule.doLerp = true; + }); + }); + } + } + + index += 1; + } + }); + + new FlxTimer().start(2, _ -> { + // dj.fistPump(); + FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); + }); + } + var touchY:Float = 0; var touchX:Float = 0; var dxTouch:Float = 0; @@ -698,10 +992,48 @@ class FreeplayState extends MusicBeatSubState var busy:Bool = false; // Set to true once the user has pressed enter to select a song. + var originalPos:FlxPoint = new FlxPoint(); + override function update(elapsed:Float):Void { super.update(elapsed); + if (FlxG.keys.justPressed.T) + { + rankAnimStart(); + } + + if (FlxG.keys.justPressed.H) + { + rankDisplayNew(); + } + + if (FlxG.keys.justPressed.G) + { + rankAnimSlam(); + } + + if (FlxG.keys.justPressed.I) + { + confirmTextGlow.y -= 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.J) + { + confirmTextGlow.x -= 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.L) + { + confirmTextGlow.x += 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.K) + { + confirmTextGlow.y += 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.F) { var targetSong = grpCapsules.members[curSelected]?.songData; @@ -1145,6 +1477,42 @@ class FreeplayState extends MusicBeatSubState FunkinSound.playOnce(Paths.sound('confirmMenu')); dj.confirm(); + grpCapsules.members[curSelected].songText.flickerText(); + + // FlxTween.color(bgDad, 0.33, 0xFFFFFFFF, 0xFF555555, {ease: FlxEase.quadOut}); + FlxTween.color(pinkBack, 0.33, 0xFFFFD0D5, 0xFF171831, {ease: FlxEase.quadOut}); + orangeBackShit.visible = false; + alsoOrangeLOL.visible = false; + + confirmGlow.visible = true; + confirmGlow2.visible = true; + + backingTextYeah.anim.play("BF back card confirm raw", false, false, 0); + confirmGlow2.alpha = 0; + confirmGlow.alpha = 0; + + FlxTween.tween(confirmGlow2, {alpha: 0.5}, 0.33, + { + ease: FlxEase.quadOut, + onComplete: function(_) { + confirmGlow2.alpha = 0.6; + confirmGlow.alpha = 1; + confirmTextGlow.visible = true; + confirmTextGlow.alpha = 1; + FlxTween.tween(confirmTextGlow, {alpha: 0.4}, 0.5); + FlxTween.tween(confirmGlow, {alpha: 0}, 0.5); + } + }); + + // confirmGlow + + moreWays.visible = false; + funnyScroll.visible = false; + txtNuts.visible = false; + funnyScroll2.visible = false; + moreWays2.visible = false; + funnyScroll3.visible = false; + new FlxTimer().start(1, function(tmr:FlxTimer) { Paths.setCurrentLevel(cap.songData.levelId); LoadingState.loadPlayState( @@ -1383,6 +1751,7 @@ class FreeplaySongData public var songName(default, null):String = ''; public var songCharacter(default, null):String = ''; + public var songStartingBpm(default, null):Float = 0; public var songRating(default, null):Int = 0; public var albumId(default, null):Null = null; @@ -1415,6 +1784,7 @@ class FreeplaySongData var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, variations); if (songDifficulty == null) return; + this.songStartingBpm = songDifficulty.getStartingBPM(); this.songName = songDifficulty.songName; this.songCharacter = songDifficulty.characters.opponent; this.songRating = songDifficulty.difficultyRating; diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index f6d85e56..0f72199b 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -14,6 +14,13 @@ import flixel.text.FlxText; import flixel.util.FlxTimer; import funkin.util.MathUtil; import funkin.graphics.shaders.Grayscale; +import funkin.graphics.shaders.GaussianBlurShader; +import openfl.display.BlendMode; +import funkin.graphics.FunkinSprite; +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import flixel.addons.effects.FlxTrail; +import flixel.util.FlxColor; class SongMenuItem extends FlxSpriteGroup { @@ -31,9 +38,10 @@ class SongMenuItem extends FlxSpriteGroup public var songText:CapsuleText; public var favIcon:FlxSprite; - public var ranking:FlxSprite; + public var ranking:FreeplayRank; + public var blurredRanking:FreeplayRank; - var ranks:Array = ["fail", "average", "great", "excellent", "perfect"]; + var ranks:Array = ["fail", "average", "great", "excellent", "perfect", "perfectsick"]; public var targetPos:FlxPoint = new FlxPoint(); public var doLerp:Bool = false; @@ -47,6 +55,22 @@ class SongMenuItem extends FlxSpriteGroup public var hsvShader(default, set):HSVShader; // var diffRatingSprite:FlxSprite; + public var bpmText:FlxSprite; + public var difficultyText:FlxSprite; + public var weekType:FlxSprite; + + public var newText:FlxSprite; + + // public var weekType:FlxSprite; + public var bigNumbers:Array = []; + + public var smallNumbers:Array = []; + + public var weekNumbers:Array = []; + + var impactThing:FunkinSprite; + + public var tempr:Int; public function new(x:Float, y:Float) { @@ -59,12 +83,64 @@ class SongMenuItem extends FlxSpriteGroup // capsule.animation add(capsule); + bpmText = new FlxSprite(144, 87).loadGraphic(Paths.image('freeplay/freeplayCapsule/bpmtext')); + bpmText.setGraphicSize(Std.int(bpmText.width * 0.9)); + add(bpmText); + + difficultyText = new FlxSprite(414, 87).loadGraphic(Paths.image('freeplay/freeplayCapsule/difficultytext')); + difficultyText.setGraphicSize(Std.int(difficultyText.width * 0.9)); + add(difficultyText); + + weekType = new FlxSprite(291, 87); + weekType.frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/weektypes'); + + weekType.animation.addByPrefix('WEEK', 'WEEK text instance 1', 24, false); + weekType.animation.addByPrefix('WEEKEND', 'WEEKEND text instance 1', 24, false); + + weekType.setGraphicSize(Std.int(weekType.width * 0.9)); + add(weekType); + + newText = new FlxSprite(454, 9); + newText.frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/new'); + newText.animation.addByPrefix('newAnim', 'NEW notif', 24, true); + newText.animation.play('newAnim', true); + newText.setGraphicSize(Std.int(newText.width * 0.9)); + + newText.visible = false; + + add(newText); + + // var debugNumber2:CapsuleNumber = new CapsuleNumber(0, 0, true, 2); + // add(debugNumber2); + + for (i in 0...2) + { + var bigNumber:CapsuleNumber = new CapsuleNumber(466 + (i * 30), 32, true, 0); + add(bigNumber); + + bigNumbers.push(bigNumber); + } + + for (i in 0...3) + { + var smallNumber:CapsuleNumber = new CapsuleNumber(185 + (i * 11), 88.5, false, 0); + add(smallNumber); + + smallNumbers.push(smallNumber); + } + // doesn't get added, simply is here to help with visibility of things for the pop in! grpHide = new FlxGroup(); var rank:String = FlxG.random.getObject(ranks); - ranking = new FlxSprite(capsule.width * 0.84, 30); + tempr = FlxG.random.int(0, 5); + ranking = new FreeplayRank(420, 41, tempr); + add(ranking); + + blurredRanking = new FreeplayRank(ranking.x, ranking.y, tempr); + blurredRanking.shader = new GaussianBlurShader(1); + add(blurredRanking); // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); // ranking.scale.x = ranking.scale.y = realScaled; // ranking.alpha = 0.75; @@ -73,11 +149,11 @@ class SongMenuItem extends FlxSpriteGroup // add(ranking); // grpHide.add(ranking); - switch (rank) - { - case 'perfect': - ranking.x -= 10; - } + // switch (rank) + // { + // case 'perfect': + // ranking.x -= 10; + // } grayscaleShader = new Grayscale(1); @@ -93,7 +169,7 @@ class SongMenuItem extends FlxSpriteGroup grpHide.add(songText); // TODO: Use value from metadata instead of random. - updateDifficultyRating(FlxG.random.int(0, 15)); + updateDifficultyRating(FlxG.random.int(0, 20)); pixelIcon = new FlxSprite(160, 35); @@ -103,21 +179,216 @@ class SongMenuItem extends FlxSpriteGroup add(pixelIcon); grpHide.add(pixelIcon); - favIcon = new FlxSprite(400, 40); + favIcon = new FlxSprite(380, 40); favIcon.frames = Paths.getSparrowAtlas('freeplay/favHeart'); favIcon.animation.addByPrefix('fav', 'favorite heart', 24, false); favIcon.animation.play('fav'); favIcon.setGraphicSize(50, 50); favIcon.visible = false; + favIcon.blend = BlendMode.ADD; add(favIcon); - // grpHide.add(favIcon); + + var weekNumber:CapsuleNumber = new CapsuleNumber(355, 88.5, false, 0); + add(weekNumber); + + weekNumbers.push(weekNumber); setVisibleGrp(false); } + // no way to grab weeks rn, so this needs to be done :/ + // negative values mean weekends + function checkWeek(name:String):Void + { + // trace(name); + var weekNum:Int = 0; + switch (name) + { + case 'bopeebo' | 'fresh' | 'dadbattle': + weekNum = 1; + case 'spookeez' | 'south' | 'monster': + weekNum = 2; + case 'pico' | 'philly-nice' | 'blammed': + weekNum = 3; + case "satin-panties" | 'high' | 'milf': + weekNum = 4; + case "cocoa" | 'eggnog' | 'winter-horrorland': + weekNum = 5; + case 'senpai' | 'roses' | 'thorns': + weekNum = 6; + case 'ugh' | 'guns' | 'stress': + weekNum = 7; + case 'darnell' | 'lit-up' | '2hot' | 'blazin': + weekNum = -1; + default: + weekNum = 0; + } + + weekNumbers[0].digit = Std.int(Math.abs(weekNum)); + + if (weekNum == 0) + { + weekType.visible = false; + weekNumbers[0].visible = false; + } + else + { + weekType.visible = true; + weekNumbers[0].visible = true; + } + if (weekNum > 0) + { + weekType.animation.play('WEEK', true); + } + else + { + weekType.animation.play('WEEKEND', true); + weekNumbers[0].offset.x -= 35; + } + } + + // 255, 27 normal + // 220, 27 favourited + public function checkClip():Void + { + var clipSize:Int = 290; + var clipType:Int = 0; + + if (ranking.visible == true) clipType += 1; + if (favIcon.visible == true) clipType += 1; + switch (clipType) + { + case 2: + clipSize = 220; + case 1: + clipSize = 255; + } + songText.clipWidth = clipSize; + } + + function updateBPM(newBPM:Int):Void + { + trace(newBPM); + + var shiftX:Float = 191; + var tempShift:Float = 0; + + if (Math.floor(newBPM / 100) == 1) + { + shiftX = 186; + } + + for (i in 0...smallNumbers.length) + { + smallNumbers[i].x = this.x + (shiftX + (i * 11)); + switch (i) + { + case 0: + if (newBPM < 100) + { + smallNumbers[i].digit = 0; + } + else + { + smallNumbers[i].digit = Math.floor(newBPM / 100) % 10; + } + + case 1: + if (newBPM < 10) + { + smallNumbers[i].digit = 0; + } + else + { + smallNumbers[i].digit = Math.floor(newBPM / 10) % 10; + + if (Math.floor(newBPM / 10) % 10 == 1) tempShift = -4; + } + case 2: + smallNumbers[i].digit = newBPM % 10; + default: + trace('why the fuck is this being called'); + } + smallNumbers[i].x += tempShift; + } + // diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}')); + // diffRatingSprite.visible = false; + } + + var evilTrail:FlxTrail; + + public function fadeAnim() + { + impactThing = new FunkinSprite(0, 0); + impactThing.frames = capsule.frames; + impactThing.frame = capsule.frame; + impactThing.updateHitbox(); + // impactThing.x = capsule.x; + // impactThing.y = capsule.y; + // picoFade.stamp(this, 0, 0); + impactThing.alpha = 0; + impactThing.zIndex = capsule.zIndex - 3; + add(impactThing); + FlxTween.tween(impactThing.scale, {x: 2.5, y: 2.5}, 0.5); + // FlxTween.tween(impactThing, {alpha: 0}, 0.5); + + evilTrail = new FlxTrail(impactThing, null, 15, 2, 0.01, 0.069); + evilTrail.blend = BlendMode.ADD; + evilTrail.zIndex = capsule.zIndex - 5; + FlxTween.tween(evilTrail, {alpha: 0}, 0.6, + { + ease: FlxEase.quadOut, + onComplete: function(_) { + remove(evilTrail); + } + }); + add(evilTrail); + + switch (tempr) + { + case 0: + evilTrail.color = 0xFF6044FF; + case 1: + evilTrail.color = 0xFFEF8764; + case 2: + evilTrail.color = 0xFFEAF6FF; + case 3: + evilTrail.color = 0xFFFDCB42; + case 4: + evilTrail.color = 0xFFFF58B4; + case 5: + evilTrail.color = 0xFFFFB619; + } + } + + public function getTrailColor():FlxColor + { + return evilTrail.color; + } + function updateDifficultyRating(newRating:Int):Void { var ratingPadded:String = newRating < 10 ? '0$newRating' : '$newRating'; + + for (i in 0...bigNumbers.length) + { + switch (i) + { + case 0: + if (newRating > 10) + { + bigNumbers[i].digit = 0; + } + else + { + bigNumbers[i].digit = Math.floor(newRating / 10); + } + case 1: + bigNumbers[i].digit = newRating % 10; + default: + trace('why the fuck is this being called'); + } + } // diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}')); // diffRatingSprite.visible = false; } @@ -169,8 +440,11 @@ class SongMenuItem extends FlxSpriteGroup // Update capsule character. if (songData?.songCharacter != null) setCharacter(songData.songCharacter); updateDifficultyRating(songData?.songRating ?? 0); + updateBPM(Std.int(songData?.songStartingBpm) ?? 0); // Update opacity, offsets, etc. updateSelected(); + + checkWeek(songData?.songId); } /** @@ -289,6 +563,28 @@ class SongMenuItem extends FlxSpriteGroup override function update(elapsed:Float):Void { + if (impactThing != null) impactThing.angle = capsule.angle; + + // if (FlxG.keys.justPressed.I) + // { + // newText.y -= 1; + // trace(this.x - newText.x, this.y - newText.y); + // } + // if (FlxG.keys.justPressed.J) + // { + // newText.x -= 1; + // trace(this.x - newText.x, this.y - newText.y); + // } + // if (FlxG.keys.justPressed.L) + // { + // newText.x += 1; + // trace(this.x - newText.x, this.y - newText.y); + // } + // if (FlxG.keys.justPressed.K) + // { + // newText.y += 1; + // trace(this.x - newText.x, this.y - newText.y); + // } if (doJumpIn) { frameInTicker += elapsed; @@ -358,5 +654,137 @@ class SongMenuItem extends FlxSpriteGroup capsule.animation.play(this.selected ? "selected" : "unselected"); ranking.alpha = this.selected ? 1 : 0.7; ranking.color = this.selected ? 0xFFFFFFFF : 0xFFAAAAAA; + + if (selected) + { + if (songText.tooLong == true) songText.initMove(); + } + else + { + if (songText.tooLong == true) songText.resetText(); + } + } +} + +class FreeplayRank extends FlxSprite +{ + public var rank(default, set):Int = 0; + + var numToRank:Array = ["LOSS", "GOOD", "GREAT", "EXCELLENT", "PERFECT", "PERFECTSICK"]; + + function set_rank(val):Int + { + animation.play(numToRank[val], true, false); + + centerOffsets(false); + + switch (val) + { + case 0: + // offset.x -= 1; + case 1: + // offset.x -= 1; + offset.y -= 8; + case 2: + // offset.x -= 1; + offset.y -= 8; + case 3: + // offset.y += 5; + case 4: + // offset.y += 5; + default: + centerOffsets(false); + } + updateHitbox(); + return val; + } + + public var baseY:Float = 0; + public var baseX:Float = 0; + + public function new(x:Float, y:Float, ?initRank:Int = 0) + { + super(x, y); + + frames = Paths.getSparrowAtlas('freeplay/rankbadges'); + + animation.addByPrefix('PERFECT', 'PERFECT rank0', 24, false); + animation.addByPrefix('EXCELLENT', 'EXCELLENT rank0', 24, false); + animation.addByPrefix('GOOD', 'GOOD rank0', 24, false); + animation.addByPrefix('PERFECTSICK', 'PERFECT rank GOLD', 24, false); + animation.addByPrefix('GREAT', 'GREAT rank0', 24, false); + animation.addByPrefix('LOSS', 'LOSS rank0', 24, false); + + blend = BlendMode.ADD; + + this.rank = initRank; + + animation.play(numToRank[initRank], true); + + // setGraphicSize(Std.int(width * 0.9)); + scale.set(0.9, 0.9); + updateHitbox(); + } +} + +class CapsuleNumber extends FlxSprite +{ + public var digit(default, set):Int = 0; + + function set_digit(val):Int + { + animation.play(numToString[val], true, false, 0); + + centerOffsets(false); + + switch (val) + { + case 1: + offset.x -= 4; + case 3: + offset.x -= 1; + + case 6: + + case 4: + // offset.y += 5; + case 9: + // offset.y += 5; + default: + centerOffsets(false); + } + return val; + } + + public var baseY:Float = 0; + public var baseX:Float = 0; + + var numToString:Array = ["ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"]; + + public function new(x:Float, y:Float, big:Bool = false, ?initDigit:Int = 0) + { + super(x, y); + + if (big) + { + frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/bignumbers'); + } + else + { + frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/smallnumbers'); + } + + for (i in 0...10) + { + var stringNum:String = numToString[i]; + animation.addByPrefix(stringNum, '$stringNum', 24, false); + } + + this.digit = initDigit; + + animation.play(numToString[initDigit], true); + + setGraphicSize(Std.int(width * 0.9)); + updateHitbox(); } } From 5f9019a2a3f9283fa96684b91ce17cd8e1ff5b23 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Thu, 30 May 2024 04:35:05 +0100 Subject: [PATCH 047/131] update assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index fe52d20d..dabdf9b1 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit fe52d20de7025d90cadb429dbdedf6d986727088 +Subproject commit dabdf9b1d361afa0f65c87b9c0f12cf90b0eebdf From b7a828e7d89756a20c7415876446ddda2c1cbd84 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 30 May 2024 05:25:51 -0400 Subject: [PATCH 048/131] Make Freeplay use correct ranks, play the slam animation after Results, new Results music --- assets | 2 +- source/funkin/InitState.hx | 4 +- source/funkin/play/PlayState.hx | 3 +- source/funkin/play/ResultState.hx | 226 ++++++--------------- source/funkin/play/scoring/Scoring.hx | 176 ++++++++++++++++ source/funkin/save/Save.hx | 13 +- source/funkin/ui/freeplay/FreeplayState.hx | 107 +++++++--- source/funkin/ui/freeplay/SongMenuItem.hx | 99 +++++---- 8 files changed, 389 insertions(+), 241 deletions(-) diff --git a/assets b/assets index 8fea0bf1..2719d3fc 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8fea0bf1fe07b6dd0efb8ecf46dc8091b0177007 +Subproject commit 2719d3fc1d8f5d0cbafae8d27141d6c471148482 diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index a945c10c..d0009f95 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -220,6 +220,8 @@ class InitState extends FlxState { storyMode: false, title: "CUM SONG", + songId: "cum", + difficultyId: "hard", isNewHighscore: true, scoreData: { @@ -227,7 +229,7 @@ class InitState extends FlxState tallies: { sick: 130, - good: 25, + good: 70, bad: 69, shit: 69, missed: 69, diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index a95166e2..e69a50b0 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -3123,9 +3123,10 @@ class PlayState extends MusicBeatSubState var res:ResultState = new ResultState( { storyMode: PlayStatePlaylist.isStoryMode, + songId: currentChart.song.id, + difficultyId: currentDifficulty, title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), prevScoreData: prevScoreData, - difficultyId: currentDifficulty, scoreData: { score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : songScore, diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index ee7c8ead..79880038 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -21,6 +21,7 @@ import funkin.audio.FunkinSound; import flixel.util.FlxGradient; import flixel.util.FlxTimer; import funkin.save.Save; +import funkin.play.scoring.Scoring; import funkin.save.Save.SaveScoreData; import funkin.graphics.shaders.LeftMaskShader; import funkin.play.components.TallyCounter; @@ -34,7 +35,7 @@ class ResultState extends MusicBeatSubState { final params:ResultsStateParams; - final rank:ResultRank; + final rank:ScoringRank; final songName:FlxBitmapText; final difficulty:FlxSprite; final clearPercentSmall:ClearPercentCounter; @@ -64,8 +65,7 @@ class ResultState extends MusicBeatSubState this.params = params; - rank = calculateRank(params); - // rank = SHIT; + rank = Scoring.calculateRank(params.scoreData) ?? SHIT; // We build a lot of this stuff in the constructor, then place it in create(). // This prevents having to do `null` checks everywhere. @@ -99,6 +99,8 @@ class ResultState extends MusicBeatSubState override function create():Void { + if (FlxG.sound.music != null) FlxG.sound.music.stop(); + // Reset the camera zoom on the results screen. FlxG.camera.zoom = 1.0; @@ -327,6 +329,33 @@ class ResultState extends MusicBeatSubState } }; + new FlxTimer().start(rank.getMusicDelay(), _ -> { + if (rank.hasMusicIntro()) + { + // Play the intro music. + var introMusic:String = Paths.music(rank.getMusicPath() + '/' + rank.getMusicPath() + '-intro'); + FunkinSound.load(introMusic, 1.0, false, true, true, () -> { + FunkinSound.playMusic(rank.getMusicPath(), + { + startingVolume: 1.0, + overrideExisting: true, + restartTrack: true, + loop: rank.shouldMusicLoop() + }); + }); + } + else + { + FunkinSound.playMusic(rank.getMusicPath(), + { + startingVolume: 1.0, + overrideExisting: true, + restartTrack: true, + loop: rank.shouldMusicLoop() + }); + } + }); + refresh(); super.create(); @@ -376,7 +405,8 @@ class ResultState extends MusicBeatSubState displayRankText(); - new FlxTimer().start(2.0, _ -> { + // previously 2.0 seconds + new FlxTimer().start(0.25, _ -> { FlxTween.tween(clearPercentCounter, {alpha: 0}, 0.5, { startDelay: 0.5, @@ -444,28 +474,6 @@ class ResultState extends MusicBeatSubState { showSmallClearPercent(); - FunkinSound.playMusic(rank.getMusicPath(), - { - startingVolume: 1.0, - overrideExisting: true, - restartTrack: true, - loop: rank.shouldMusicLoop() - }); - - FlxG.sound.music.onComplete = () -> { - if (rank == SHIT) - { - FunkinSound.playMusic('bluu', - { - startingVolume: 0.0, - overrideExisting: true, - restartTrack: true, - loop: true - }); - FlxG.sound.music.fadeIn(10.0, 0.0, 1.0); - } - } - switch (rank) { case PERFECT | PERFECT_GOLD: @@ -478,7 +486,6 @@ class ResultState extends MusicBeatSubState bfPerfect.visible = true; bfPerfect.playAnimation(''); } - case EXCELLENT: if (bfExcellent == null) { @@ -489,7 +496,6 @@ class ResultState extends MusicBeatSubState bfExcellent.visible = true; bfExcellent.playAnimation('Intro'); } - case GREAT: if (bfGreat == null) { @@ -500,7 +506,6 @@ class ResultState extends MusicBeatSubState bfGreat.visible = true; bfGreat.playAnimation('Intro'); } - case SHIT: if (bfShit == null) { @@ -511,7 +516,6 @@ class ResultState extends MusicBeatSubState bfShit.visible = true; bfShit.playAnimation('Intro'); } - case GOOD: if (bfGood == null) { @@ -521,7 +525,6 @@ class ResultState extends MusicBeatSubState { bfGood.animation.play('fall'); bfGood.visible = true; - new FlxTimer().start((1 / 24) * 22, _ -> { // plays about 22 frames (at 24fps timing) after bf spawns in if (gfGood != null) @@ -635,154 +638,39 @@ class ResultState extends MusicBeatSubState if (controls.PAUSE) { - FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8); - FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1, - { - onComplete: _ -> { - FlxTween.tween(FlxG.sound.music, {pitch: 0.5}, 0.4); - } - }); + if (FlxG.sound.music != null) + { + FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8); + FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1, + { + onComplete: _ -> { + FlxTween.tween(FlxG.sound.music, {pitch: 0.5}, 0.4); + } + }); + } if (params.storyMode) { openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker))); } else { - openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(null, sticker))); + openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build( + { + { + fromResults: + { + oldRank: Scoring.calculateRank(params?.prevScoreData), + newRank: rank, + songId: params.songId, + difficultyId: params.difficultyId + } + } + }, sticker))); } } super.update(elapsed); } - - public static function calculateRank(params:ResultsStateParams):ResultRank - { - // Perfect (Platinum) is a Sick Full Clear - var isPerfectGold = params.scoreData.tallies.sick == params.scoreData.tallies.totalNotes; - if (isPerfectGold) return ResultRank.PERFECT_GOLD; - - // Else, use the standard grades - - // Grade % (only good and sick), 1.00 is a full combo - var grade = (params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes; - // Clear % (including bad and shit). 1.00 is a full clear but not a full combo - var clear = (params.scoreData.tallies.totalNotesHit) / params.scoreData.tallies.totalNotes; - - if (grade == Constants.RANK_PERFECT_THRESHOLD) - { - return ResultRank.PERFECT; - } - else if (grade >= Constants.RANK_EXCELLENT_THRESHOLD) - { - return ResultRank.EXCELLENT; - } - else if (grade >= Constants.RANK_GREAT_THRESHOLD) - { - return ResultRank.GREAT; - } - else if (grade >= Constants.RANK_GOOD_THRESHOLD) - { - return ResultRank.GOOD; - } - else - { - return ResultRank.SHIT; - } - } -} - -enum abstract ResultRank(String) -{ - var PERFECT_GOLD; - var PERFECT; - var EXCELLENT; - var GREAT; - var GOOD; - var SHIT; - - public function getMusicPath():String - { - switch (abstract) - { - case PERFECT_GOLD: - return 'resultsPERFECT'; - case PERFECT: - return 'resultsPERFECT'; - case EXCELLENT: - return 'resultsNORMAL'; - case GREAT: - return 'resultsNORMAL'; - case GOOD: - return 'resultsNORMAL'; - case SHIT: - return 'resultsSHIT'; - default: - return 'resultsNORMAL'; - } - } - - public function shouldMusicLoop():Bool - { - switch (abstract) - { - case PERFECT_GOLD: - return true; - case PERFECT: - return true; - case EXCELLENT: - return true; - case GREAT: - return true; - case GOOD: - return true; - case SHIT: - return false; - default: - return false; - } - } - - public function getHorTextAsset() - { - switch (abstract) - { - case PERFECT_GOLD: - return 'resultScreen/rankText/rankScrollPERFECT'; - case PERFECT: - return 'resultScreen/rankText/rankScrollPERFECT'; - case EXCELLENT: - return 'resultScreen/rankText/rankScrollEXCELLENT'; - case GREAT: - return 'resultScreen/rankText/rankScrollGREAT'; - case GOOD: - return 'resultScreen/rankText/rankScrollGOOD'; - case SHIT: - return 'resultScreen/rankText/rankScrollLOSS'; - default: - return 'resultScreen/rankText/rankScrollGOOD'; - } - } - - public function getVerTextAsset() - { - switch (abstract) - { - case PERFECT_GOLD: - return 'resultScreen/rankText/rankTextPERFECT'; - case PERFECT: - return 'resultScreen/rankText/rankTextPERFECT'; - case EXCELLENT: - return 'resultScreen/rankText/rankTextEXCELLENT'; - case GREAT: - return 'resultScreen/rankText/rankTextGREAT'; - case GOOD: - return 'resultScreen/rankText/rankTextGOOD'; - case SHIT: - return 'resultScreen/rankText/rankTextLOSS'; - default: - return 'resultScreen/rankText/rankTextGOOD'; - } - } } typedef ResultsStateParams = @@ -797,6 +685,8 @@ typedef ResultsStateParams = */ var title:String; + var songId:String; + /** * Whether the displayed score is a new highscore */ diff --git a/source/funkin/play/scoring/Scoring.hx b/source/funkin/play/scoring/Scoring.hx index 744091b4..6155ec87 100644 --- a/source/funkin/play/scoring/Scoring.hx +++ b/source/funkin/play/scoring/Scoring.hx @@ -1,5 +1,7 @@ package funkin.play.scoring; +import funkin.save.Save.SaveScoreData; + /** * Which system to use when scoring and judging notes. */ @@ -344,4 +346,178 @@ class Scoring return 'miss'; } } + + public static function calculateRank(scoreData:Null):Null + { + if (scoreData == null) return null; + + // Perfect (Platinum) is a Sick Full Clear + var isPerfectGold = scoreData.tallies.sick == scoreData.tallies.totalNotes; + if (isPerfectGold) return ScoringRank.PERFECT_GOLD; + + // Else, use the standard grades + + // Grade % (only good and sick), 1.00 is a full combo + var grade = (scoreData.tallies.sick + scoreData.tallies.good) / scoreData.tallies.totalNotes; + // Clear % (including bad and shit). 1.00 is a full clear but not a full combo + var clear = (scoreData.tallies.totalNotesHit) / scoreData.tallies.totalNotes; + + if (grade == Constants.RANK_PERFECT_THRESHOLD) + { + return ScoringRank.PERFECT; + } + else if (grade >= Constants.RANK_EXCELLENT_THRESHOLD) + { + return ScoringRank.EXCELLENT; + } + else if (grade >= Constants.RANK_GREAT_THRESHOLD) + { + return ScoringRank.GREAT; + } + else if (grade >= Constants.RANK_GOOD_THRESHOLD) + { + return ScoringRank.GOOD; + } + else + { + return ScoringRank.SHIT; + } + } +} + +enum abstract ScoringRank(String) +{ + var PERFECT_GOLD; + var PERFECT; + var EXCELLENT; + var GREAT; + var GOOD; + var SHIT; + + /** + * Delay in seconds + */ + public function getMusicDelay():Float + { + switch (abstract) + { + case PERFECT_GOLD | PERFECT: + // return 2.5; + return 5.0; + case EXCELLENT: + return 1.75; + default: + return 3.5; + } + } + + public function getMusicPath():String + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultsPERFECT'; + case PERFECT: + return 'resultsPERFECT'; + case EXCELLENT: + return 'resultsEXCELLENT'; + case GREAT: + return 'resultsNORMAL'; + case GOOD: + return 'resultsNORMAL'; + case SHIT: + return 'resultsSHIT'; + default: + return 'resultsNORMAL'; + } + } + + public function hasMusicIntro():Bool + { + switch (abstract) + { + case EXCELLENT: + return true; + case SHIT: + return true; + default: + return false; + } + } + + public function getFreeplayRankIconAsset():Null + { + switch (abstract) + { + case PERFECT_GOLD: + return 'PERFECTSICK'; + case PERFECT: + return 'PERFECT'; + case EXCELLENT: + return 'EXCELLENT'; + case GREAT: + return 'GREAT'; + case GOOD: + return 'GOOD'; + case SHIT: + return 'LOSS'; + default: + return null; + } + } + + public function shouldMusicLoop():Bool + { + switch (abstract) + { + case PERFECT_GOLD | PERFECT | EXCELLENT | GREAT | GOOD: + return true; + case SHIT: + return false; + default: + return false; + } + } + + public function getHorTextAsset() + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultScreen/rankText/rankScrollPERFECT'; + case PERFECT: + return 'resultScreen/rankText/rankScrollPERFECT'; + case EXCELLENT: + return 'resultScreen/rankText/rankScrollEXCELLENT'; + case GREAT: + return 'resultScreen/rankText/rankScrollGREAT'; + case GOOD: + return 'resultScreen/rankText/rankScrollGOOD'; + case SHIT: + return 'resultScreen/rankText/rankScrollLOSS'; + default: + return 'resultScreen/rankText/rankScrollGOOD'; + } + } + + public function getVerTextAsset() + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultScreen/rankText/rankTextPERFECT'; + case PERFECT: + return 'resultScreen/rankText/rankTextPERFECT'; + case EXCELLENT: + return 'resultScreen/rankText/rankTextEXCELLENT'; + case GREAT: + return 'resultScreen/rankText/rankTextGREAT'; + case GOOD: + return 'resultScreen/rankText/rankTextGOOD'; + case SHIT: + return 'resultScreen/rankText/rankTextLOSS'; + default: + return 'resultScreen/rankText/rankTextGOOD'; + } + } } diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 934d6a4a..7f25a8e0 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -1,15 +1,17 @@ package funkin.save; import flixel.util.FlxSave; -import funkin.save.migrator.SaveDataMigrator; -import thx.semver.Version; import funkin.input.Controls.Device; +import funkin.play.scoring.Scoring; +import funkin.play.scoring.Scoring.ScoringRank; import funkin.save.migrator.RawSaveData_v1_0_0; import funkin.save.migrator.SaveDataMigrator; +import funkin.save.migrator.SaveDataMigrator; import funkin.ui.debug.charting.ChartEditorState.ChartEditorLiveInputStyle; import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme; -import thx.semver.Version; import funkin.util.SerializerUtil; +import thx.semver.Version; +import thx.semver.Version; @:nullSafety class Save @@ -492,6 +494,11 @@ class Save return song.get(difficultyId); } + public function getSongRank(songId:String, difficultyId:String = 'normal'):Null + { + return Scoring.calculateRank(getSongScore(songId, difficultyId)); + } + /** * Apply the score the user achieved for a given song on a given difficulty. */ diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 530f28c3..904a2ca4 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -34,6 +34,8 @@ import funkin.play.song.Song; import funkin.save.Save; import funkin.save.Save.SaveScoreData; import funkin.ui.AtlasText; +import funkin.play.scoring.Scoring; +import funkin.play.scoring.Scoring.ScoringRank; import funkin.ui.mainmenu.MainMenuState; import funkin.ui.MusicBeatSubState; import funkin.ui.transition.LoadingState; @@ -49,6 +51,34 @@ import funkin.effects.IntervalShake; typedef FreeplayStateParams = { ?character:String, + + ?fromResults:FromResultsParams, +}; + +/** + * A set of parameters for transitioning to the FreeplayState from the ResultsState. + */ +typedef FromResultsParams = +{ + /** + * The previous rank the song hand, if any. Null if it had no score before. + */ + var ?oldRank:ScoringRank; + + /** + * The new rank the song has. + */ + var newRank:ScoringRank; + + /** + * The song ID to play the animation on. + */ + var songId:String; + + /** + * The difficulty ID to play the animation on. + */ + var difficultyId:String; }; /** @@ -160,10 +190,14 @@ class FreeplayState extends MusicBeatSubState var bgDad:FlxSprite; var cardGlow:FlxSprite; + var fromResultsParams:Null = null; + public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { currentCharacter = params?.character ?? Constants.DEFAULT_CHARACTER; + fromResultsParams = params?.fromResults; + if (stickers != null) { stickerSubState = stickers; @@ -587,6 +621,11 @@ class FreeplayState extends MusicBeatSubState cardGlow.visible = true; FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut}); + + if (fromResultsParams != null) + { + rankAnimStart(fromResultsParams); + } }); generateSongList(null, false); @@ -657,6 +696,12 @@ class FreeplayState extends MusicBeatSubState // If curSelected is 0, the result will be null and fall back to the rememberedSongId. rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId ?? rememberedSongId; + if (fromResultsParams != null) + { + rememberedSongId = fromResultsParams.songId; + rememberedDifficulty = fromResultsParams.difficultyId; + } + for (cap in grpCapsules.members) { cap.songText.resetText(); @@ -763,8 +808,10 @@ class FreeplayState extends MusicBeatSubState return songsToFilter; } - function rankAnimStart() + function rankAnimStart(fromResults:Null):Void { + busy = true; + dj.fistPump(); // rankCamera.fade(FlxColor.BLACK, 0.5, true); rankCamera.fade(0xFF000000, 0.5, true, null, true); @@ -789,21 +836,21 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(0.5, _ -> { grpCapsules.members[curSelected].doLerp = false; - rankDisplayNew(); + rankDisplayNew(fromResults); }); } - function rankDisplayNew() + function rankDisplayNew(fromResults:Null):Void { grpCapsules.members[curSelected].ranking.alpha = 1; grpCapsules.members[curSelected].blurredRanking.alpha = 1; grpCapsules.members[curSelected].ranking.scale.set(20, 20); grpCapsules.members[curSelected].blurredRanking.scale.set(20, 20); - // var tempr:Int = FlxG.random.int(0, 4); - // grpCapsules.members[curSelected].ranking.rank = tempr; - grpCapsules.members[curSelected].ranking.animation.play(grpCapsules.members[curSelected].ranking.animation.curAnim.name, true); + grpCapsules.members[curSelected].ranking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true); + // grpCapsules.members[curSelected].ranking.animation.curAnim.name, true); + FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1); grpCapsules.members[curSelected].blurredRanking.animation.play(grpCapsules.members[curSelected].blurredRanking.animation.curAnim.name, true); @@ -811,13 +858,13 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(0.1, _ -> { trace(grpCapsules.members[curSelected].ranking.rank); - switch (grpCapsules.members[curSelected].tempr) + switch (fromResultsParams?.newRank) { - case 0: + case SHIT: FunkinSound.playOnce(Paths.sound('ranks/rankinbad')); - case 4: + case PERFECT: FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); - case 5: + case PERFECT_GOLD: FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); default: FunkinSound.playOnce(Paths.sound('ranks/rankinnormal')); @@ -846,31 +893,31 @@ class FreeplayState extends MusicBeatSubState }); new FlxTimer().start(0.6, _ -> { - rankAnimSlam(); + rankAnimSlam(fromResults); // IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0, 0.3, FlxEase.quartIn); }); } - function rankAnimSlam() + function rankAnimSlam(fromResultsParams:Null) { // FlxTween.tween(rankCamera, {"zoom": 1.9}, 0.5, {ease: FlxEase.backOut}); FlxTween.tween(rankBg, {alpha: 0}, 0.5, {ease: FlxEase.expoIn}); // FlxTween.tween(grpCapsules.members[curSelected], {angle: 5}, 0.5, {ease: FlxEase.backIn}); - switch (grpCapsules.members[curSelected].tempr) + switch (fromResultsParams?.newRank) { - case 0: + case SHIT: FunkinSound.playOnce(Paths.sound('ranks/loss')); - case 1: + case GOOD: FunkinSound.playOnce(Paths.sound('ranks/good')); - case 2: + case GREAT: FunkinSound.playOnce(Paths.sound('ranks/great')); - case 3: + case EXCELLENT: FunkinSound.playOnce(Paths.sound('ranks/excellent')); - case 4: + case PERFECT: FunkinSound.playOnce(Paths.sound('ranks/perfect')); - case 5: + case PERFECT_GOLD: FunkinSound.playOnce(Paths.sound('ranks/perfect')); default: FunkinSound.playOnce(Paths.sound('ranks/loss')); @@ -880,7 +927,7 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(0.5, _ -> { funnyCam.shake(0.0045, 0.35); - if (grpCapsules.members[curSelected].tempr == 0) + if (fromResultsParams?.newRank == SHIT) { dj.pumpFistBad(); } @@ -915,6 +962,9 @@ class FreeplayState extends MusicBeatSubState IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12, 0, FlxEase.quadOut, function(_) { capsule.doLerp = true; capsule.cameras = [funnyCam]; + + // NOW we can interact with the menu + busy = false; }, null); // FlxTween.tween(capsule, {"targetPos.x": capsule.targetPos.x - 50}, 0.6, @@ -981,7 +1031,10 @@ class FreeplayState extends MusicBeatSubState var spamTimer:Float = 0; var spamming:Bool = false; - var busy:Bool = false; // Set to true once the user has pressed enter to select a song. + /** + * If true, disable interaction with the interface. + */ + var busy:Bool = false; var originalPos:FlxPoint = new FlxPoint(); @@ -989,19 +1042,20 @@ class FreeplayState extends MusicBeatSubState { super.update(elapsed); + #if debug if (FlxG.keys.justPressed.T) { - rankAnimStart(); + rankAnimStart(fromResultsParams); } if (FlxG.keys.justPressed.H) { - rankDisplayNew(); + rankDisplayNew(fromResultsParams); } if (FlxG.keys.justPressed.G) { - rankAnimSlam(); + rankAnimSlam(fromResultsParams); } if (FlxG.keys.justPressed.I) @@ -1024,6 +1078,7 @@ class FreeplayState extends MusicBeatSubState confirmTextGlow.y += 1; trace(confirmTextGlow.x, confirmTextGlow.y); } + #end if (FlxG.keys.justPressed.F) { @@ -1765,6 +1820,8 @@ class FreeplaySongData public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY; + public var scoringRank:Null = null; + var displayedVariations:Array = [Constants.DEFAULT_VARIATION]; function set_currentDifficulty(value:String):String @@ -1827,6 +1884,8 @@ class FreeplaySongData { this.albumId = songDifficulty.album; } + + this.scoringRank = Save.instance.getSongRank(songId, currentDifficulty); } } diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index 536a9cfe..ad6ea386 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -20,6 +20,7 @@ import funkin.graphics.FunkinSprite; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.addons.effects.FlxTrail; +import funkin.play.scoring.Scoring.ScoringRank; import flixel.util.FlxColor; class SongMenuItem extends FlxSpriteGroup @@ -70,8 +71,6 @@ class SongMenuItem extends FlxSpriteGroup var impactThing:FunkinSprite; - public var tempr:Int; - public function new(x:Float, y:Float) { super(x, y); @@ -132,13 +131,10 @@ class SongMenuItem extends FlxSpriteGroup // doesn't get added, simply is here to help with visibility of things for the pop in! grpHide = new FlxGroup(); - var rank:String = FlxG.random.getObject(ranks); - - tempr = FlxG.random.int(0, 5); - ranking = new FreeplayRank(420, 41, tempr); + ranking = new FreeplayRank(420, 41); add(ranking); - blurredRanking = new FreeplayRank(ranking.x, ranking.y, tempr); + blurredRanking = new FreeplayRank(ranking.x, ranking.y); blurredRanking.shader = new GaussianBlurShader(1); add(blurredRanking); // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); @@ -344,19 +340,19 @@ class SongMenuItem extends FlxSpriteGroup }); add(evilTrail); - switch (tempr) + switch (ranking.rank) { - case 0: + case SHIT: evilTrail.color = 0xFF6044FF; - case 1: + case GOOD: evilTrail.color = 0xFFEF8764; - case 2: + case GREAT: evilTrail.color = 0xFFEAF6FF; - case 3: + case EXCELLENT: evilTrail.color = 0xFFFDCB42; - case 4: + case PERFECT: evilTrail.color = 0xFFFF58B4; - case 5: + case PERFECT_GOLD: evilTrail.color = 0xFFFFB619; } } @@ -393,6 +389,12 @@ class SongMenuItem extends FlxSpriteGroup // diffRatingSprite.visible = false; } + function updateScoringRank(newRank:Null):Void + { + this.ranking.rank = newRank; + this.blurredRanking.rank = newRank; + } + function set_hsvShader(value:HSVShader):HSVShader { this.hsvShader = value; @@ -441,6 +443,7 @@ class SongMenuItem extends FlxSpriteGroup if (songData?.songCharacter != null) setCharacter(songData.songCharacter); updateBPM(Std.int(songData?.songStartingBpm) ?? 0); updateDifficultyRating(songData?.difficultyRating ?? 0); + updateScoringRank(songData?.scoringRank); // Update opacity, offsets, etc. updateSelected(); @@ -668,41 +671,53 @@ class SongMenuItem extends FlxSpriteGroup class FreeplayRank extends FlxSprite { - public var rank(default, set):Int = 0; + public var rank(default, set):Null = null; - var numToRank:Array = ["LOSS", "GOOD", "GREAT", "EXCELLENT", "PERFECT", "PERFECTSICK"]; - - function set_rank(val):Int + function set_rank(val:Null):Null { - animation.play(numToRank[val], true, false); + rank = val; - centerOffsets(false); - - switch (val) + if (rank == null) { - case 0: - // offset.x -= 1; - case 1: - // offset.x -= 1; - offset.y -= 8; - case 2: - // offset.x -= 1; - offset.y -= 8; - case 3: - // offset.y += 5; - case 4: - // offset.y += 5; - default: - centerOffsets(false); + this.visible = false; } - updateHitbox(); - return val; + else + { + this.visible = true; + + animation.play(val.getFreeplayRankIconAsset(), true, false); + + centerOffsets(false); + + switch (val) + { + case SHIT: + // offset.x -= 1; + case GOOD: + // offset.x -= 1; + offset.y -= 8; + case GREAT: + // offset.x -= 1; + offset.y -= 8; + case EXCELLENT: + // offset.y += 5; + case PERFECT: + // offset.y += 5; + case PERFECT_GOLD: + // offset.y += 5; + default: + centerOffsets(false); + } + updateHitbox(); + } + + return rank = val; } - public var baseY:Float = 0; public var baseX:Float = 0; + public var baseY:Float = 0; - public function new(x:Float, y:Float, ?initRank:Int = 0) + public function new(x:Float, y:Float) { super(x, y); @@ -717,9 +732,7 @@ class FreeplayRank extends FlxSprite blend = BlendMode.ADD; - this.rank = initRank; - - animation.play(numToRank[initRank], true); + this.rank = null; // setGraphicSize(Std.int(width * 0.9)); scale.set(0.9, 0.9); From 7a2f3c81a1d5cbb02c376256361eadb953cc9e6d Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 30 May 2024 21:11:17 -0400 Subject: [PATCH 049/131] fix the one random slice of pixels where the bg doesnt show... lol --- source/funkin/ui/title/TitleState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index c9b3619e..c6dbcd50 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -124,7 +124,7 @@ class TitleState extends MusicBeatState persistentUpdate = true; - var bg:FunkinSprite = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, FlxColor.BLACK); + var bg:FunkinSprite = new FunkinSprite(-1).makeSolidColor(FlxG.width + 2, FlxG.height, FlxColor.BLACK); bg.screenCenter(); add(bg); From dc33da904cc51d2ce1cf08aa3af1030863ae86f3 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 30 May 2024 23:03:27 -0400 Subject: [PATCH 050/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 2719d3fc..4bc0b35f 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 2719d3fc1d8f5d0cbafae8d27141d6c471148482 +Subproject commit 4bc0b35f6c7aa22086b85b6a635c6f0511d277fe From 7347b66ce47570b6098085945cd561d6fe0f2154 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 30 May 2024 23:07:41 -0400 Subject: [PATCH 051/131] removes trace() that lags freeplay --- source/funkin/ui/freeplay/SongMenuItem.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index ad6ea386..75a4c07a 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -264,8 +264,6 @@ class SongMenuItem extends FlxSpriteGroup function updateBPM(newBPM:Int):Void { - trace(newBPM); - var shiftX:Float = 191; var tempShift:Float = 0; From 40d1fd96a36bf566437d2dafdb716ffafee9e212 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 30 May 2024 23:27:00 -0400 Subject: [PATCH 052/131] art submod --- art | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/art b/art index 66572f85..faeba700 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit 66572f85d826ce2ec1d45468c12733b161237ffa +Subproject commit faeba700c5526bd4fd57ccc927d875c82b9d3553 From 007ec95e8548892e70189e782081201624211827 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 30 May 2024 23:42:48 -0400 Subject: [PATCH 053/131] update difficulties --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 4bc0b35f..11bcd1b7 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4bc0b35f6c7aa22086b85b6a635c6f0511d277fe +Subproject commit 11bcd1b79169df4f0aa46d72c867e960a287d28a From 0d4f3cdc334c8593fe7b1042d1c2295adf69992e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 01:42:41 -0400 Subject: [PATCH 054/131] Scrolling results text --- assets | 2 +- source/funkin/InitState.hx | 4 +-- source/funkin/play/ResultState.hx | 44 ++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/assets b/assets index 11bcd1b7..7a0d92d3 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 11bcd1b79169df4f0aa46d72c867e960a287d28a +Subproject commit 7a0d92d3007de42c452b2ea97a917d8c8d114ee7 diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index d0009f95..c7a08d71 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -219,9 +219,9 @@ class InitState extends FlxState FlxG.switchState(() -> new funkin.play.ResultState( { storyMode: false, - title: "CUM SONG", + title: "Cum Song Erect by Kawai Sprite", songId: "cum", - difficultyId: "hard", + difficultyId: "nightmare", isNewHighscore: true, scoreData: { diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 79880038..8b8c0aea 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -15,8 +15,10 @@ import funkin.ui.freeplay.FreeplayScore; import flixel.text.FlxText; import flixel.util.FlxColor; import flixel.tweens.FlxEase; +import funkin.graphics.FunkinCamera; import funkin.ui.freeplay.FreeplayState; import flixel.tweens.FlxTween; +import flixel.addons.display.FlxBackdrop; import funkin.audio.FunkinSound; import flixel.util.FlxGradient; import flixel.util.FlxTimer; @@ -59,6 +61,10 @@ class ResultState extends MusicBeatSubState var gfGood:Null = null; var bfShit:Null = null; + final cameraBG:FunkinCamera; + final cameraScroll:FunkinCamera; + final cameraEverything:FunkinCamera; + public function new(params:ResultsStateParams) { super(); @@ -67,6 +73,10 @@ class ResultState extends MusicBeatSubState rank = Scoring.calculateRank(params.scoreData) ?? SHIT; + cameraBG = new FunkinCamera('resultsBG', 0, 0, FlxG.width, FlxG.height); + cameraScroll = new FunkinCamera('resultsScroll', 0, 0, FlxG.width, FlxG.height); + cameraEverything = new FunkinCamera('resultsEverything', 0, 0, FlxG.width, FlxG.height); + // We build a lot of this stuff in the constructor, then place it in create(). // This prevents having to do `null` checks everywhere. @@ -101,17 +111,32 @@ class ResultState extends MusicBeatSubState { if (FlxG.sound.music != null) FlxG.sound.music.stop(); + // We need multiple cameras so we can put one at an angle. + cameraScroll.angle = -3.8; + + cameraBG.bgColor = FlxColor.MAGENTA; + cameraScroll.bgColor = FlxColor.TRANSPARENT; + cameraEverything.bgColor = FlxColor.TRANSPARENT; + + FlxG.cameras.add(cameraBG, false); + FlxG.cameras.add(cameraScroll, false); + FlxG.cameras.add(cameraEverything, false); + + FlxG.cameras.setDefaultDrawTarget(cameraEverything, true); + // Reset the camera zoom on the results screen. FlxG.camera.zoom = 1.0; var bg:FlxSprite = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFECC5C, 0xFFFDC05C], 90); bg.scrollFactor.set(); bg.zIndex = 10; + bg.cameras = [cameraBG]; add(bg); bgFlash.scrollFactor.set(); bgFlash.visible = false; bgFlash.zIndex = 20; + bgFlash.cameras = [cameraBG]; add(bgFlash); // The sound system which falls into place behind the score text. Plays every time! @@ -455,16 +480,27 @@ class ResultState extends MusicBeatSubState function displayRankText():Void { - var rankTextVert:FunkinSprite = FunkinSprite.create(FlxG.width - 64, 100, rank.getVerTextAsset()); - rankTextVert.zIndex = 2000; + var rankTextVert:FlxBackdrop = new FlxBackdrop(Paths.image(rank.getVerTextAsset()), Y, 0, 30); + rankTextVert.x = FlxG.width - 64; + rankTextVert.y = 100; + rankTextVert.zIndex = 990; add(rankTextVert); + // Scrolling. + rankTextVert.velocity.y = -50; + for (i in 0...10) { - var rankTextBack:FunkinSprite = FunkinSprite.create(FlxG.width / 2 - 80, 50, rank.getHorTextAsset()); - rankTextBack.y += (rankTextBack.height * i / 2) + 10; + var rankTextBack:FlxBackdrop = new FlxBackdrop(Paths.image(rank.getHorTextAsset()), X, 10, 0); + rankTextBack.x = FlxG.width / 2 - 320; + rankTextBack.y = 50 + (150 * i / 2) + 10; + // rankTextBack.angle = -3.8; rankTextBack.zIndex = 100; + rankTextBack.cameras = [cameraScroll]; add(rankTextBack); + + // Scrolling. + rankTextBack.velocity.x = (i % 2 == 0) ? -10.0 : 10.0; } refresh(); From 9e0a99374691f8a3018dc547a49c7c400b9245a7 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 02:03:40 -0400 Subject: [PATCH 055/131] Disable song previews for mod songs rather than crashing the game --- source/funkin/audio/FunkinSound.hx | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index b94c6008..7663c130 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -377,7 +377,7 @@ class FunkinSound extends FlxSound implements ICloneable FlxG.sound.music = partialMusic; FlxG.sound.list.remove(FlxG.sound.music); - if (params.onLoad != null) params.onLoad(); + if (FlxG.sound.music != null && params.onLoad != null) params.onLoad(); }); return true; @@ -488,14 +488,21 @@ class FunkinSound extends FlxSound implements ICloneable var soundRequest = FlxPartialSound.partialLoadFromFile(path, start, end); - promise.future.onError(function(e) { - soundRequest.error("Sound loading was errored or cancelled"); - }); + if (soundRequest == null) + { + promise.complete(null); + } + else + { + promise.future.onError(function(e) { + soundRequest.error("Sound loading was errored or cancelled"); + }); - soundRequest.future.onComplete(function(partialSound) { - var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad); - promise.complete(snd); - }); + soundRequest.future.onComplete(function(partialSound) { + var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad); + promise.complete(snd); + }); + } return promise; } From 2a8cdfaffae9dca58c0957f825f491ec89bd8070 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 02:30:42 -0400 Subject: [PATCH 056/131] Fix an extra crash. --- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 192c6e3c..f0695e51 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -830,7 +830,7 @@ class FreeplayState extends MusicBeatSubState dj.fistPump(); // rankCamera.fade(FlxColor.BLACK, 0.5, true); rankCamera.fade(0xFF000000, 0.5, true, null, true); - FlxG.sound.music.volume = 0; + if (FlxG.sound.music != null) FlxG.sound.music.volume = 0; rankBg.alpha = 1; originalPos.x = grpCapsules.members[curSelected].x; From 1e65cacb0efaa92991fd2290fe6f30b58e38ba7d Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Fri, 31 May 2024 10:39:06 +0100 Subject: [PATCH 057/131] fix funkinsound compile error --- source/funkin/audio/FunkinSound.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index b94c6008..cf4a7118 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -359,7 +359,7 @@ class FunkinSound extends FlxSound implements ICloneable if (shouldLoadPartial) { - var music = FunkinSound.loadPartial(pathToUse, params.partialParams?.start ?? 0, params.partialParams?.end ?? 1, params?.startingVolume ?? 1.0, + var music = FunkinSound.loadPartial(pathToUse, params.partialParams?.start ?? 0.0, params.partialParams?.end ?? 1.0, params?.startingVolume ?? 1.0, params.loop ?? true, false, false, params.onComplete); if (music != null) From 28444fd47814a4c3833310743d7d5ce1944ec9e9 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Fri, 31 May 2024 10:39:53 +0100 Subject: [PATCH 058/131] rank tweaks, favourite changes + rank anim fixes --- source/funkin/play/ResultState.hx | 61 +++++++++-- source/funkin/play/scoring/Scoring.hx | 58 ++++++++++- source/funkin/ui/credits/CreditsState.hx | 3 +- source/funkin/ui/freeplay/AlbumRoll.hx | 2 +- source/funkin/ui/freeplay/FreeplayState.hx | 112 +++++++++++++++++---- source/funkin/ui/freeplay/SongMenuItem.hx | 7 +- source/funkin/ui/mainmenu/MainMenuState.hx | 13 ++- 7 files changed, 220 insertions(+), 36 deletions(-) diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 79880038..1ad19b41 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -59,6 +59,8 @@ class ResultState extends MusicBeatSubState var gfGood:Null = null; var bfShit:Null = null; + var rankBg:FunkinSprite; + public function new(params:ResultsStateParams) { super(); @@ -95,6 +97,8 @@ class ResultState extends MusicBeatSubState highscoreNew = new FlxSprite(310, 570); score = new ResultScore(35, 305, 10, params.scoreData.score); + + rankBg = new FunkinSprite(0, 0); } override function create():Void @@ -356,6 +360,12 @@ class ResultState extends MusicBeatSubState } }); + rankBg.makeSolidColor(FlxG.width, FlxG.height, 0xFF000000); + rankBg.zIndex = 99999; + add(rankBg); + + rankBg.alpha = 0; + refresh(); super.create(); @@ -654,18 +664,47 @@ class ResultState extends MusicBeatSubState } else { - openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build( - { + var rigged:Bool = true; + if (rank > Scoring.calculateRank(params?.prevScoreData)) + //if (rigged) + { + trace('THE RANK IS Higher.....'); + + FlxTween.tween(rankBg, {alpha: 1}, 0.5, { - fromResults: - { - oldRank: Scoring.calculateRank(params?.prevScoreData), - newRank: rank, - songId: params.songId, - difficultyId: params.difficultyId - } - } - }, sticker))); + ease: FlxEase.expoOut, + onComplete: function(_) { + FlxG.switchState(FreeplayState.build( + { + { + fromResults: + { + oldRank: Scoring.calculateRank(params?.prevScoreData), + newRank: rank, + songId: params.songId, + difficultyId: params.difficultyId + } + } + })); + } + }); + } + else + { + trace('rank is lower...... and/or equal'); + openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build( + { + { + fromResults: + { + oldRank: null, + newRank: rank, + songId: params.songId, + difficultyId: params.difficultyId + } + } + }, sticker))); + } } } diff --git a/source/funkin/play/scoring/Scoring.hx b/source/funkin/play/scoring/Scoring.hx index 6155ec87..f941f3f0 100644 --- a/source/funkin/play/scoring/Scoring.hx +++ b/source/funkin/play/scoring/Scoring.hx @@ -349,7 +349,7 @@ class Scoring public static function calculateRank(scoreData:Null):Null { - if (scoreData == null) return null; + if (scoreData?.tallies.totalNotes == 0 || scoreData == null) return null; // Perfect (Platinum) is a Sick Full Clear var isPerfectGold = scoreData.tallies.sick == scoreData.tallies.totalNotes; @@ -394,6 +394,62 @@ enum abstract ScoringRank(String) var GOOD; var SHIT; + @:op(A > B) static function compare(a:Null, b:Null):Bool + { + if (a != null && b == null) return true; + if (a == null || b == null) return false; + + var temp1:Int = 0; + var temp2:Int = 0; + + // temp 1 + switch (a) + { + case PERFECT_GOLD: + temp1 = 5; + case PERFECT: + temp1 = 4; + case EXCELLENT: + temp1 = 3; + case GREAT: + temp1 = 2; + case GOOD: + temp1 = 1; + case SHIT: + temp1 = 0; + default: + temp1 = -1; + } + + // temp 2 + switch (b) + { + case PERFECT_GOLD: + temp2 = 5; + case PERFECT: + temp2 = 4; + case EXCELLENT: + temp2 = 3; + case GREAT: + temp2 = 2; + case GOOD: + temp2 = 1; + case SHIT: + temp2 = 0; + default: + temp2 = -1; + } + + if (temp1 > temp2) + { + return true; + } + else + { + return false; + } + } + /** * Delay in seconds */ diff --git a/source/funkin/ui/credits/CreditsState.hx b/source/funkin/ui/credits/CreditsState.hx index 6be1fecf..44769e9b 100644 --- a/source/funkin/ui/credits/CreditsState.hx +++ b/source/funkin/ui/credits/CreditsState.hx @@ -4,6 +4,7 @@ import flixel.text.FlxText; import flixel.util.FlxColor; import funkin.audio.FunkinSound; import flixel.FlxSprite; +import funkin.ui.mainmenu.MainMenuState; import flixel.group.FlxSpriteGroup; /** @@ -199,7 +200,7 @@ class CreditsState extends MusicBeatState function exit():Void { - FlxG.switchState(funkin.ui.mainmenu.MainMenuState.new); + FlxG.switchState(() -> new MainMenuState()); } public override function destroy():Void diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx index 50f4a432..20cd9137 100644 --- a/source/funkin/ui/freeplay/AlbumRoll.hx +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -131,7 +131,7 @@ class AlbumRoll extends FlxSpriteGroup if (exitMovers == null) return; - exitMovers.set([newAlbumArt], + exitMovers.set([newAlbumArt, difficultyStars], { x: FlxG.width, speed: 0.4, diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 192c6e3c..186c84c3 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -193,12 +193,18 @@ class FreeplayState extends MusicBeatSubState var fromResultsParams:Null = null; + var prepForNewRank:Bool = false; + public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { currentCharacter = params?.character ?? Constants.DEFAULT_CHARACTER; fromResultsParams = params?.fromResults; + if(fromResultsParams?.oldRank != null){ + prepForNewRank = true; + } + if (stickers != null) { stickerSubState = stickers; @@ -235,11 +241,14 @@ class FreeplayState extends MusicBeatSubState isDebug = true; #end - FunkinSound.playMusic('freakyMenu', + if (prepForNewRank == false) + { + FunkinSound.playMusic('freakyMenu', { overrideExisting: true, restartTrack: false }); + } // Add a null entry that represents the RANDOM option songs.push(null); @@ -637,7 +646,7 @@ class FreeplayState extends MusicBeatSubState cardGlow.visible = true; FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut}); - if (fromResultsParams != null) + if (prepForNewRank == true) { rankAnimStart(fromResultsParams); } @@ -667,6 +676,11 @@ class FreeplayState extends MusicBeatSubState FlxG.cameras.add(rankCamera, false); rankBg.cameras = [rankCamera]; rankBg.alpha = 0; + + if (prepForNewRank == true) + { + rankCamera.fade(0xFF000000, 0, false, null, true); + } } var currentFilter:SongFilter = null; @@ -826,6 +840,7 @@ class FreeplayState extends MusicBeatSubState function rankAnimStart(fromResults:Null):Void { busy = true; + // grpCapsules.members[curSelected].forcePosition(); dj.fistPump(); // rankCamera.fade(FlxColor.BLACK, 0.5, true); @@ -833,8 +848,14 @@ class FreeplayState extends MusicBeatSubState FlxG.sound.music.volume = 0; rankBg.alpha = 1; - originalPos.x = grpCapsules.members[curSelected].x; - originalPos.y = grpCapsules.members[curSelected].y; + grpCapsules.members[curSelected].doLerp = false; + + // originalPos.x = grpCapsules.members[curSelected].x; + // originalPos.y = grpCapsules.members[curSelected].y; + + originalPos.x = 320.488; + originalPos.y = 235.6; + trace(originalPos); grpCapsules.members[curSelected].ranking.alpha = 0; grpCapsules.members[curSelected].blurredRanking.alpha = 0; @@ -846,11 +867,13 @@ class FreeplayState extends MusicBeatSubState FlxTween.tween(funnyCam, {"zoom": 1.1}, 0.6, {ease: FlxEase.sineIn}); grpCapsules.members[curSelected].cameras = [rankCamera]; - grpCapsules.members[curSelected].targetPos.set((FlxG.width / 2) - (grpCapsules.members[curSelected].width / 2), + // grpCapsules.members[curSelected].targetPos.set((FlxG.width / 2) - (grpCapsules.members[curSelected].width / 2), + // (FlxG.height / 2) - (grpCapsules.members[curSelected].height / 2)); + + grpCapsules.members[curSelected].setPosition((FlxG.width / 2) - (grpCapsules.members[curSelected].width / 2), (FlxG.height / 2) - (grpCapsules.members[curSelected].height / 2)); new FlxTimer().start(0.5, _ -> { - grpCapsules.members[curSelected].doLerp = false; rankDisplayNew(fromResults); }); } @@ -1028,6 +1051,12 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(2, _ -> { // dj.fistPump(); + prepForNewRank = false; + FunkinSound.playMusic('freakyMenu', + { + overrideExisting: true, + restartTrack: false + }); FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); }); } @@ -1095,7 +1124,7 @@ class FreeplayState extends MusicBeatSubState } #end - if (FlxG.keys.justPressed.F) + if (FlxG.keys.justPressed.F && !busy) { var targetSong = grpCapsules.members[curSelected]?.songData; if (targetSong != null) @@ -1104,24 +1133,45 @@ class FreeplayState extends MusicBeatSubState var isFav = targetSong.toggleFavorite(); if (isFav) { - FlxTween.tween(grpCapsules.members[realShit], {angle: 360}, 0.4, + grpCapsules.members[realShit].favIcon.visible = true; + grpCapsules.members[realShit].favIcon.animation.play('fav'); + FunkinSound.playOnce(Paths.sound('fav'), 1); + busy = true; + + grpCapsules.members[realShit].doLerp = false; + FlxTween.tween(grpCapsules.members[realShit], {y: grpCapsules.members[realShit].y - 5}, 0.1, {ease: FlxEase.expoOut}); + + FlxTween.tween(grpCapsules.members[realShit], {y: grpCapsules.members[realShit].y + 5}, 0.1, { - ease: FlxEase.elasticOut, - onComplete: _ -> { - grpCapsules.members[realShit].favIcon.visible = true; - grpCapsules.members[realShit].favIcon.animation.play('fav'); + ease: FlxEase.expoIn, + startDelay: 0.1, + onComplete: function(_) { + grpCapsules.members[realShit].doLerp = true; + busy = false; } }); } else { - grpCapsules.members[realShit].favIcon.animation.play('fav', false, true); - new FlxTimer().start((1 / 24) * 14, _ -> { + grpCapsules.members[realShit].favIcon.animation.play('fav', true, true, 9); + FunkinSound.playOnce(Paths.sound('unfav'), 1); + new FlxTimer().start(0.2, _ -> { grpCapsules.members[realShit].favIcon.visible = false; }); - new FlxTimer().start((1 / 24) * 24, _ -> { - FlxTween.tween(grpCapsules.members[realShit], {angle: 0}, 0.4, {ease: FlxEase.elasticOut}); - }); + + busy = true; + grpCapsules.members[realShit].doLerp = false; + FlxTween.tween(grpCapsules.members[realShit], {y: grpCapsules.members[realShit].y + 5}, 0.1, {ease: FlxEase.expoOut}); + + FlxTween.tween(grpCapsules.members[realShit], {y: grpCapsules.members[realShit].y - 5}, 0.1, + { + ease: FlxEase.expoIn, + startDelay: 0.1, + onComplete: function(_) { + grpCapsules.members[realShit].doLerp = true; + busy = false; + } + }); } } } @@ -1325,6 +1375,24 @@ class FreeplayState extends MusicBeatSubState var longestTimer:Float = 0; + // FlxTween.color(bgDad, 0.33, 0xFFFFFFFF, 0xFF555555, {ease: FlxEase.quadOut}); + FlxTween.color(pinkBack, 0.25, 0xFFFFD863, 0xFFFFD0D5, {ease: FlxEase.quadOut}); + + cardGlow.visible = true; + cardGlow.alpha = 1; + cardGlow.scale.set(1, 1); + FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.25, {ease: FlxEase.sineOut}); + + orangeBackShit.visible = false; + alsoOrangeLOL.visible = false; + + moreWays.visible = false; + funnyScroll.visible = false; + txtNuts.visible = false; + funnyScroll2.visible = false; + moreWays2.visible = false; + funnyScroll3.visible = false; + for (grpSpr in exitMovers.keys()) { var moveData:MoveData = exitMovers.get(grpSpr); @@ -1555,6 +1623,7 @@ class FreeplayState extends MusicBeatSubState FunkinSound.playOnce(Paths.sound('confirmMenu')); dj.confirm(); + grpCapsules.members[curSelected].forcePosition(); grpCapsules.members[curSelected].songText.flickerText(); // FlxTween.color(bgDad, 0.33, 0xFFFFFFFF, 0xFF555555, {ease: FlxEase.quadOut}); @@ -1689,6 +1758,7 @@ class FreeplayState extends MusicBeatSubState } else { + if(prepForNewRank == false){ var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; // TODO: Stream the instrumental of the selected song? FunkinSound.playMusic(daSongCapsule.songData.songId, @@ -1708,6 +1778,7 @@ class FreeplayState extends MusicBeatSubState FlxG.sound.music.fadeIn(2, 0, 0.4); } }); + } } grpCapsules.members[curSelected].selected = true; } @@ -1719,7 +1790,12 @@ class FreeplayState extends MusicBeatSubState */ public static function build(?params:FreeplayStateParams, ?stickers:StickerSubState):MusicBeatState { - var result = new MainMenuState(); + var result:MainMenuState; + if(params?.fromResults.oldRank != null){ + result = new MainMenuState(true); + }else{ + result = new MainMenuState(false); + } result.openSubState(new FreeplayState(params, stickers)); result.persistentUpdate = false; diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index ad6ea386..b52032bc 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -371,7 +371,7 @@ class SongMenuItem extends FlxSpriteGroup switch (i) { case 0: - if (newRating > 10) + if (newRating < 10) { bigNumbers[i].digit = 0; } @@ -677,7 +677,7 @@ class FreeplayRank extends FlxSprite { rank = val; - if (rank == null) + if (rank == null || val == null) { this.visible = false; } @@ -687,6 +687,8 @@ class FreeplayRank extends FlxSprite animation.play(val.getFreeplayRankIconAsset(), true, false); + trace(val.getFreeplayRankIconAsset()); + centerOffsets(false); switch (val) @@ -707,6 +709,7 @@ class FreeplayRank extends FlxSprite // offset.y += 5; default: centerOffsets(false); + this.visible = false; } updateHitbox(); } diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx index 22262006..c504b3c3 100644 --- a/source/funkin/ui/mainmenu/MainMenuState.hx +++ b/source/funkin/ui/mainmenu/MainMenuState.hx @@ -42,6 +42,15 @@ class MainMenuState extends MusicBeatState var magenta:FlxSprite; var camFollow:FlxObject; + var overrideMusic:Bool = false; + + public function new(?_overrideMusic:Bool = false) + { + super(); + overrideMusic = _overrideMusic; + + } + override function create():Void { #if discord_rpc @@ -54,7 +63,7 @@ class MainMenuState extends MusicBeatState transIn = FlxTransitionableState.defaultTransIn; transOut = FlxTransitionableState.defaultTransOut; - playMenuMusic(); + if(overrideMusic == false) playMenuMusic(); // We want the state to always be able to begin with being able to accept inputs and show the anims of the menu items. persistentUpdate = true; @@ -163,7 +172,7 @@ class MainMenuState extends MusicBeatState function playMenuMusic():Void { - FunkinSound.playMusic('freakyMenu', + FunkinSound.playMusic('freakyMenu', { overrideExisting: true, restartTrack: false From 5d0db60810b37e3a076e3581ed2b33416ed1050c Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Fri, 31 May 2024 10:40:51 +0100 Subject: [PATCH 059/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 4bc0b35f..d64939d8 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4bc0b35f6c7aa22086b85b6a635c6f0511d277fe +Subproject commit d64939d866c70a831b76ed78930782b66871dcc2 From d89a898e6c3d33430002896bd601ec72c6a0faba Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 31 May 2024 17:16:26 -0400 Subject: [PATCH 060/131] make songs last longer on freeplay --- source/funkin/ui/freeplay/FreeplayState.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 192c6e3c..71052a92 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -104,6 +104,7 @@ class FreeplayState extends MusicBeatSubState /** * For the audio preview, the duration of the fade-out effect. + * */ public static final FADE_OUT_DURATION:Float = 0.25; @@ -1690,7 +1691,6 @@ class FreeplayState extends MusicBeatSubState else { var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; - // TODO: Stream the instrumental of the selected song? FunkinSound.playMusic(daSongCapsule.songData.songId, { startingVolume: 0.0, @@ -1701,8 +1701,8 @@ class FreeplayState extends MusicBeatSubState partialParams: { loadPartial: true, - start: 0, - end: 0.1 + start: 0.05, + end: 0.25 }, onLoad: function() { FlxG.sound.music.fadeIn(2, 0, 0.4); From 98eda8ef551ad533b29a5a1625ec613b78165c5e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 18:09:07 -0400 Subject: [PATCH 061/131] Give timeFormat a default value (fixes the Stress issues!) --- source/funkin/data/song/SongData.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index bd25139a..ca805e13 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -56,6 +56,8 @@ class SongMetadata implements ICloneable @:default(funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY) public var generatedBy:String; + @:optional + @:default(funkin.data.song.SongData.SongTimeFormat.MILLISECONDS) public var timeFormat:SongTimeFormat; public var timeChanges:Array; @@ -117,7 +119,7 @@ class SongMetadata implements ICloneable { var ignoreNullOptionals = true; var writer = new json2object.JsonWriter(ignoreNullOptionals); - // I believe @:jignored should be iggnored by the writer? + // I believe @:jignored should be ignored by the writer? // var output = this.clone(); // output.variation = null; // Not sure how to make a field optional on the reader and ignored on the writer. return writer.write(this, pretty ? ' ' : null); From 8bf26322e9a405e3eb70508711b66a606cd444a6 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 18:09:30 -0400 Subject: [PATCH 062/131] Update `generatedBy` to the latest value when saving a chart. --- .../ChartEditorImportExportHandler.hx | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx index 0308cd87..a78eeae4 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx @@ -384,17 +384,32 @@ class ChartEditorImportExportHandler if (variationId == '') { var variationMetadata:Null = state.songMetadata.get(variation); - if (variationMetadata != null) zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-metadata.json', variationMetadata.serialize())); + if (variationMetadata != null) + { + variationMetadata.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; + zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-metadata.json', variationMetadata.serialize())); + } var variationChart:Null = state.songChartData.get(variation); - if (variationChart != null) zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-chart.json', variationChart.serialize())); + if (variationChart != null) + { + variationChart.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; + zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-chart.json', variationChart.serialize())); + } } else { var variationMetadata:Null = state.songMetadata.get(variation); - if (variationMetadata != null) zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-metadata-$variationId.json', - variationMetadata.serialize())); + if (variationMetadata != null) + { + variationMetadata.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; + zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-metadata-$variationId.json', variationMetadata.serialize())); + } var variationChart:Null = state.songChartData.get(variation); - if (variationChart != null) zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-chart-$variationId.json', variationChart.serialize())); + if (variationChart != null) + { + variationChart.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; + zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-chart-$variationId.json', variationChart.serialize())); + } } } From 06daa9d402a81bb45b5bf214595b4d0ac794fd4c Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 19:20:39 -0400 Subject: [PATCH 063/131] Increase Great threshold to 80% --- source/funkin/util/Constants.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 4e706c61..1e097883 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -467,7 +467,7 @@ class Constants // % Hit public static final RANK_PERFECT_THRESHOLD:Float = 1.00; public static final RANK_EXCELLENT_THRESHOLD:Float = 0.90; - public static final RANK_GREAT_THRESHOLD:Float = 0.75; + public static final RANK_GREAT_THRESHOLD:Float = 0.80; public static final RANK_GOOD_THRESHOLD:Float = 0.60; // public static final RANK_SHIT_THRESHOLD:Float = 0.00; From 9088570b926eae749c5cc6822dbb01cd1d541f69 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 19:21:21 -0400 Subject: [PATCH 064/131] Make sure JSON data uses latest version/generatedBy when writing. --- source/funkin/data/song/SongData.hx | 24 +++++++++++++++++++ .../data/song/importer/ChartManifestData.hx | 8 +++++++ source/funkin/data/stage/StageData.hx | 8 +++++++ .../funkin/ui/credits/CreditsDataHandler.hx | 2 +- .../ChartEditorImportExportHandler.hx | 4 +++- 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index ca805e13..769af8f0 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -117,6 +117,9 @@ class SongMetadata implements ICloneable */ public function serialize(pretty:Bool = true):String { + // Update generatedBy and version before writing. + updateVersionToLatest(); + var ignoreNullOptionals = true; var writer = new json2object.JsonWriter(ignoreNullOptionals); // I believe @:jignored should be ignored by the writer? @@ -125,6 +128,12 @@ class SongMetadata implements ICloneable return writer.write(this, pretty ? ' ' : null); } + public function updateVersionToLatest():Void + { + this.version = SongRegistry.SONG_METADATA_VERSION; + this.generatedBy = SongRegistry.DEFAULT_GENERATEDBY; + } + /** * Produces a string representation suitable for debugging. */ @@ -373,6 +382,12 @@ class SongMusicData implements ICloneable this.variation = variation == null ? Constants.DEFAULT_VARIATION : variation; } + public function updateVersionToLatest():Void + { + this.version = SongRegistry.SONG_MUSIC_DATA_VERSION; + this.generatedBy = SongRegistry.DEFAULT_GENERATEDBY; + } + public function clone():SongMusicData { var result:SongMusicData = new SongMusicData(this.songName, this.artist, this.variation); @@ -605,11 +620,20 @@ class SongChartData implements ICloneable */ public function serialize(pretty:Bool = true):String { + // Update generatedBy and version before writing. + updateVersionToLatest(); + var ignoreNullOptionals = true; var writer = new json2object.JsonWriter(ignoreNullOptionals); return writer.write(this, pretty ? ' ' : null); } + public function updateVersionToLatest():Void + { + this.version = SongRegistry.SONG_CHART_DATA_VERSION; + this.generatedBy = SongRegistry.DEFAULT_GENERATEDBY; + } + public function clone():SongChartData { // We have to manually perform the deep clone here because Map.deepClone() doesn't work. diff --git a/source/funkin/data/song/importer/ChartManifestData.hx b/source/funkin/data/song/importer/ChartManifestData.hx index dd0d2847..04b5a1b6 100644 --- a/source/funkin/data/song/importer/ChartManifestData.hx +++ b/source/funkin/data/song/importer/ChartManifestData.hx @@ -61,10 +61,18 @@ class ChartManifestData */ public function serialize(pretty:Bool = true):String { + // Update generatedBy and version before writing. + updateVersionToLatest(); + var writer = new json2object.JsonWriter(); return writer.write(this, pretty ? ' ' : null); } + public function updateVersionToLatest():Void + { + this.version = CHART_MANIFEST_DATA_VERSION; + } + public static function deserialize(contents:String):Null { var parser = new json2object.JsonParser(); diff --git a/source/funkin/data/stage/StageData.hx b/source/funkin/data/stage/StageData.hx index 22b883c7..bebd86d0 100644 --- a/source/funkin/data/stage/StageData.hx +++ b/source/funkin/data/stage/StageData.hx @@ -58,9 +58,17 @@ class StageData */ public function serialize(pretty:Bool = true):String { + // Update generatedBy and version before writing. + updateVersionToLatest(); + var writer = new json2object.JsonWriter(); return writer.write(this, pretty ? ' ' : null); } + + public function updateVersionToLatest():Void + { + this.version = StageRegistry.STAGE_DATA_VERSION; + } } typedef StageDataCharacters = diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx index 2240ec50..844d0f4d 100644 --- a/source/funkin/ui/credits/CreditsDataHandler.hx +++ b/source/funkin/ui/credits/CreditsDataHandler.hx @@ -54,7 +54,7 @@ class CreditsDataHandler body: [ {line: 'ninjamuffin99'}, {line: 'PhantomArcade'}, - {line: 'KawaiSprite'}, + {line: 'Kawai Sprite'}, {line: 'evilsk8r'}, ] } diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx index a78eeae4..e84f7ec4 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx @@ -386,12 +386,14 @@ class ChartEditorImportExportHandler var variationMetadata:Null = state.songMetadata.get(variation); if (variationMetadata != null) { + variationMetadata.version = funkin.data.song.SongRegistry.SONG_METADATA_VERSION; variationMetadata.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-metadata.json', variationMetadata.serialize())); } var variationChart:Null = state.songChartData.get(variation); if (variationChart != null) { + variationChart.version = funkin.data.song.SongRegistry.SONG_CHART_DATA_VERSION; variationChart.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-chart.json', variationChart.serialize())); } @@ -401,12 +403,12 @@ class ChartEditorImportExportHandler var variationMetadata:Null = state.songMetadata.get(variation); if (variationMetadata != null) { - variationMetadata.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-metadata-$variationId.json', variationMetadata.serialize())); } var variationChart:Null = state.songChartData.get(variation); if (variationChart != null) { + variationChart.version = funkin.data.song.SongRegistry.SONG_CHART_DATA_VERSION; variationChart.generatedBy = funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY; zipEntries.push(FileUtil.makeZIPEntry('${state.currentSongId}-chart-$variationId.json', variationChart.serialize())); } From 074b1afc7659cf0923a03533994a812c9f39ef8d Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 20:16:23 -0400 Subject: [PATCH 065/131] Readd a reverted freeplay bugfix --- source/funkin/audio/FunkinSound.hx | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index b94c6008..7663c130 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -377,7 +377,7 @@ class FunkinSound extends FlxSound implements ICloneable FlxG.sound.music = partialMusic; FlxG.sound.list.remove(FlxG.sound.music); - if (params.onLoad != null) params.onLoad(); + if (FlxG.sound.music != null && params.onLoad != null) params.onLoad(); }); return true; @@ -488,14 +488,21 @@ class FunkinSound extends FlxSound implements ICloneable var soundRequest = FlxPartialSound.partialLoadFromFile(path, start, end); - promise.future.onError(function(e) { - soundRequest.error("Sound loading was errored or cancelled"); - }); + if (soundRequest == null) + { + promise.complete(null); + } + else + { + promise.future.onError(function(e) { + soundRequest.error("Sound loading was errored or cancelled"); + }); - soundRequest.future.onComplete(function(partialSound) { - var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad); - promise.complete(snd); - }); + soundRequest.future.onComplete(function(partialSound) { + var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad); + promise.complete(snd); + }); + } return promise; } From e36fbfa72c79bf2ac793e1a78a80b0559c9cba64 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 20:16:37 -0400 Subject: [PATCH 066/131] Update the changelog --- CHANGELOG.md | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10bbfe5f..f5aefb88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,31 +6,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.4.0] - 2024-05-?? ### Added -- 2 new Erect remixes, Eggnog and Satin Panties. Check them out from -- Improvements to the Freeplay screen, with song difficulty ratings and player rank displays. -- Reworked the Results screen, with additional animations and audio based on your performance. +- 2 new Erect remixes, Eggnog and Satin Panties. Check them out from the Freeplay menu! +- Major visual improvements to the Results screen, with additional animations and audio based on your performance. +- Major visual improvements to the Freeplay screen, with song difficulty ratings and player rank displays. + - Freeplay now plays a preview of songs when you hover over them. - Added a Charter field to the chart format, to allow for crediting the creator of a level's chart. - You can see who charted a song from the Pause menu. +- Added a new Scroll Speed chart event to change the note speed mid-song (thanks ) ### Changed - Tweaked the charts for several songs: + - Monster - Winter Horrorland - Stress - Lit Up + - Tutorial (increased the note speed slightly) + - Senpai (increased the note speed) + - Thorns (increased the note speed slightly) +- Favorite songs marked in Freeplay are now stored between sessions. - Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!) +- Improved logic for NoteHitScriptEvents, allowing you to view the hit diff and modify whether a note hit is a combo break (thanks nebulazorua!) - Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!) - Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame. ### Fixed +- Fixed a bug where the game would silently fail to load saves on HTML5 +- Fixed some bugs with the props on the Story Menu not bopping properly +- Additional fixes to the Loading bar on HTML5 (thanks lemz1!) +- Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!) +- Fixed a camera bug in the Main Menu (thanks richTrash21!) +- Fixed a bug where changing difficulties in Story mode wouldn't update the score (thanks sectorA!) +- Fixed a crash in Freeplay caused by a level referencing an invalid song (thanks gamerbross!) - Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!) -- Fixed a bug where the Chart Editor would crash when losing (thanks gamerbross!) +- Fixed a bug where the Chart Editor Playtest would crash when losing (thanks gamerbross!) +- Fixed a bug where hold notes would display improperly in the Chart Editor when downscroll was enabled for gameplay (thanks gamerbross!) +- Fixed a bug where hold notes would be positioned wrong on downscroll (thanks MaybeMaru!) +- Removed a large number of unused imports to optimize builds (thanks Ethan-makes-music!) +- Improved debug logging for unscripted stages (thanks gamerbross!) - Made improvements to compiling documentation (thanks gedehari!) - Fixed a crash on Linux caused by an old version of hxCodec (thanks Noobz4Life!) - Optimized animation handling for characters (thanks richTrash21!) +- Additional bug fixes and optimizations. ## [0.3.3] - 2024-05-14 ### Changed - Cleaned up some code in `PlayAnimationSongEvent.hx` (thanks BurgerBalls!) ### Fixed -- Fix Web Loading Bar (thanks lemz1!) +- Fixes to the Loading bar on HTML5 (thanks lemz1!) - Don't allow any more inputs when exiting freeplay (thanks gamerbros!) - Fixed using mouse wheel to scroll on freeplay (thanks JugieNoob!) - Fixed the reset's of the health icons, score, and notes when re-entering gameplay from gameover (thanks ImCodist!) @@ -38,11 +58,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed camera stutter once a wipe transition to the Main Menu completes (thanks ImCodist!) - Fixed an issue where hold note would be invisible for a single frame (thanks ImCodist!) - Fix tween accumulation on title screen when pressing Y multiple times (thanks TheGaloXx!) -- Fix for a game over easter egg so you don't accidentally exit it when viewing - Fix a crash when querying FlxG.state in the crash handler +- Fix for a game over easter egg so you don't accidentally exit it when viewing - Fix an issue where the Freeplay menu never displays 100% clear +- Fix an issue where Weekend 1 Pico attempted to retrieve a missing asset. +- Fix an issue where duplicate keybinds would be stoed, potentially causing a crash - Chart debug key now properly returns you to the previous chart editor session if you were playtesting a chart (thanks nebulazorua!) -- Hopefully fixed Freeplay crashes on AMD gpu's +- Fix a crash on Freeplay found on AMD graphics cards ## [0.3.2] - 2024-05-03 ### Added From e08cdac35bfa3c57540d90d21118797d2e244fde Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sat, 1 Jun 2024 01:16:52 +0100 Subject: [PATCH 067/131] score number shuffling --- source/funkin/play/ResultScore.hx | 80 +++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/source/funkin/play/ResultScore.hx b/source/funkin/play/ResultScore.hx index d5d5a656..23e6c8d3 100644 --- a/source/funkin/play/ResultScore.hx +++ b/source/funkin/play/ResultScore.hx @@ -2,11 +2,16 @@ package funkin.play; import flixel.FlxSprite; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; +import flixel.tweens.FlxTween; +import flixel.util.FlxTimer; +import flixel.tweens.FlxEase; class ResultScore extends FlxTypedSpriteGroup { public var scoreShit(default, set):Int = 0; + public var scoreStart:Int = 0; + function set_scoreShit(val):Int { if (group == null || group.members == null) return val; @@ -16,7 +21,8 @@ class ResultScore extends FlxTypedSpriteGroup while (dumbNumb > 0) { - group.members[loopNum].digit = dumbNumb % 10; + scoreStart += 1; + group.members[loopNum].finalDigit = dumbNumb % 10; // var funnyNum = group.members[loopNum]; // prevNum = group.members[loopNum + 1]; @@ -44,9 +50,15 @@ class ResultScore extends FlxTypedSpriteGroup public function animateNumbers():Void { - for (i in group.members) + for (i in group.members.length-scoreStart...group.members.length) { - i.playAnim(); + // if(i.finalDigit == 10) continue; + + new FlxTimer().start((i-1)/24, _ -> { + group.members[i].finalDelay = scoreStart - (i-1); + group.members[i].playAnim(); + group.members[i].shuffle(); + }); } } @@ -71,12 +83,26 @@ class ResultScore extends FlxTypedSpriteGroup class ScoreNum extends FlxSprite { public var digit(default, set):Int = 10; + public var finalDigit(default, set):Int = 10; + public var glow:Bool = true; + + function set_finalDigit(val):Int + { + animation.play('GONE', true, false, 0); + + return finalDigit = val; + } function set_digit(val):Int { if (val >= 0 && animation.curAnim != null && animation.curAnim.name != numToString[val]) { - animation.play(numToString[val], true, false, 0); + if(glow){ + animation.play(numToString[val], true, false, 0); + glow = false; + }else{ + animation.play(numToString[val], true, false, 4); + } updateHitbox(); switch (val) @@ -107,6 +133,10 @@ class ScoreNum extends FlxSprite animation.play(numToString[digit], true, false, 0); } + public var shuffleTimer:FlxTimer; + public var finalTween:FlxTween; + public var finalDelay:Float = 0; + public var baseY:Float = 0; public var baseX:Float = 0; @@ -114,6 +144,47 @@ class ScoreNum extends FlxSprite "ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "DISABLED" ]; + function finishShuffleTween():Void{ + + var tweenFunction = function(x) { + var digitRounded = Math.floor(x); + //if(digitRounded == finalDigit) glow = true; + digit = digitRounded; + }; + + finalTween = FlxTween.num(0.0, finalDigit, 23/24, { + ease: FlxEase.quadOut, + onComplete: function (input) { + new FlxTimer().start((finalDelay)/24, _ -> { + animation.play(animation.curAnim.name, true, false, 0); + }); + // fuck + } + }, tweenFunction); + } + + + function shuffleProgress(shuffleTimer:FlxTimer):Void + { + var tempDigit:Int = digit; + tempDigit += 1; + if(tempDigit > 9) tempDigit = 0; + if(tempDigit < 0) tempDigit = 0; + digit = tempDigit; + + if (shuffleTimer.loops > 0 && shuffleTimer.loopsLeft == 0) + { + //digit = finalDigit; + finishShuffleTween(); + } + } + + public function shuffle():Void{ + var duration:Float = 41/24; + var interval:Float = 1/24; + shuffleTimer = new FlxTimer().start(interval, shuffleProgress, Std.int(duration / interval)); + } + public function new(x:Float, y:Float) { super(x, y); @@ -130,6 +201,7 @@ class ScoreNum extends FlxSprite } animation.addByPrefix('DISABLED', 'DISABLED', 24, false); + animation.addByPrefix('GONE', 'GONE', 24, false); this.digit = 10; From 1cffc36ba8aa51b90523ff7fbe4464eca957cc29 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sat, 1 Jun 2024 01:17:11 +0100 Subject: [PATCH 068/131] results timing redo + fixed anims for all ranks --- source/funkin/play/ResultState.hx | 280 +++++++++++++++++++++----- source/funkin/play/scoring/Scoring.hx | 70 ++++++- 2 files changed, 293 insertions(+), 57 deletions(-) diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 8b8c0aea..8a7332a8 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -5,6 +5,7 @@ import funkin.ui.story.StoryMenuState; import funkin.graphics.adobeanimate.FlxAtlasSprite; import flixel.FlxSprite; import funkin.graphics.FunkinSprite; +import flixel.effects.FlxFlicker; import flixel.graphics.frames.FlxBitmapFont; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.math.FlxPoint; @@ -55,8 +56,10 @@ class ResultState extends MusicBeatSubState final score:ResultScore; var bfPerfect:Null = null; + var heartsPerfect:Null = null; var bfExcellent:Null = null; var bfGreat:Null = null; + var gfGreat:Null = null; var bfGood:Null = null; var gfGood:Null = null; var bfShit:Null = null; @@ -94,15 +97,15 @@ class ResultState extends MusicBeatSubState clearPercentSmall.zIndex = 1000; clearPercentSmall.visible = false; - bgFlash = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFEB69, 0xFFFFE66A], 90); + bgFlash = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFF1A6, 0xFFFFF1BE], 90); resultsAnim = FunkinSprite.createSparrow(-200, -10, "resultScreen/results"); - ratingsPopin = FunkinSprite.createSparrow(-150, 120, "resultScreen/ratingsPopin"); + ratingsPopin = FunkinSprite.createSparrow(-135, 135, "resultScreen/ratingsPopin"); - scorePopin = FunkinSprite.createSparrow(-180, 520, "resultScreen/scorePopin"); + scorePopin = FunkinSprite.createSparrow(-180, 515, "resultScreen/scorePopin"); - highscoreNew = new FlxSprite(310, 570); + highscoreNew = new FlxSprite(44, 557); score = new ResultScore(35, 305, 10, params.scoreData.score); } @@ -136,14 +139,14 @@ class ResultState extends MusicBeatSubState bgFlash.scrollFactor.set(); bgFlash.visible = false; bgFlash.zIndex = 20; - bgFlash.cameras = [cameraBG]; + //bgFlash.cameras = [cameraBG]; add(bgFlash); // The sound system which falls into place behind the score text. Plays every time! var soundSystem:FlxSprite = FunkinSprite.createSparrow(-15, -180, 'resultScreen/soundSystem'); soundSystem.animation.addByPrefix("idle", "sound system", 24, false); soundSystem.visible = false; - new FlxTimer().start(0.3, _ -> { + new FlxTimer().start(8/24, _ -> { soundSystem.animation.play("idle"); soundSystem.visible = true; }); @@ -153,7 +156,22 @@ class ResultState extends MusicBeatSubState switch (rank) { case PERFECT | PERFECT_GOLD: - bfPerfect = new FlxAtlasSprite(370, -180, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT", "shared")); + heartsPerfect = new FlxAtlasSprite(1342, 370, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT/hearts", "shared")); + heartsPerfect.visible = false; + heartsPerfect.zIndex = 501; + add(heartsPerfect); + + heartsPerfect.anim.onComplete = () -> { + if (heartsPerfect != null) + { + //bfPerfect.anim.curFrame = 137; + heartsPerfect.anim.curFrame = 43; + heartsPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! + } + }; + + + bfPerfect = new FlxAtlasSprite(1342, 370, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT", "shared")); bfPerfect.visible = false; bfPerfect.zIndex = 500; add(bfPerfect); @@ -161,36 +179,57 @@ class ResultState extends MusicBeatSubState bfPerfect.anim.onComplete = () -> { if (bfPerfect != null) { + //bfPerfect.anim.curFrame = 137; bfPerfect.anim.curFrame = 137; bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! } }; case EXCELLENT: - bfExcellent = new FlxAtlasSprite(380, -170, Paths.animateAtlas("resultScreen/results-bf/resultsEXCELLENT", "shared")); + bfExcellent = new FlxAtlasSprite(1329, 429, Paths.animateAtlas("resultScreen/results-bf/resultsEXCELLENT", "shared")); bfExcellent.visible = false; bfExcellent.zIndex = 500; add(bfExcellent); - bfExcellent.onAnimationFinish.add((animName) -> { + bfExcellent.anim.onComplete = () -> { if (bfExcellent != null) { - bfExcellent.playAnimation('Loop Start'); + bfExcellent.anim.curFrame = 28; + bfExcellent.anim.play(); // unpauses this anim, since it's on PlayOnce! } - }); + }; + case GREAT: - bfGreat = new FlxAtlasSprite(640, 200, Paths.animateAtlas("resultScreen/results-bf/resultsGREAT", "shared")); + gfGreat = new FlxAtlasSprite(802, 331, Paths.animateAtlas("resultScreen/results-bf/resultsGREAT/gf", "shared")); + gfGreat.visible = false; + gfGreat.zIndex = 499; + add(gfGreat); + + gfGreat.scale.set(0.93, 0.93); + + gfGreat.anim.onComplete = () -> { + if (gfGreat != null) + { + gfGreat.anim.curFrame = 9; + gfGreat.anim.play(); // unpauses this anim, since it's on PlayOnce! + } + }; + + bfGreat = new FlxAtlasSprite(929, 363, Paths.animateAtlas("resultScreen/results-bf/resultsGREAT/bf", "shared")); bfGreat.visible = false; bfGreat.zIndex = 500; add(bfGreat); - bfGreat.onAnimationFinish.add((animName) -> { + bfGreat.scale.set(0.93, 0.93); + + bfGreat.anim.onComplete = () -> { if (bfGreat != null) { - bfGreat.playAnimation('Loop Start'); + bfGreat.anim.curFrame = 15; + bfGreat.anim.play(); // unpauses this anim, since it's on PlayOnce! } - }); + }; case GOOD: gfGood = FunkinSprite.createSparrow(625, 325, 'resultScreen/results-bf/resultsGOOD/resultGirlfriendGOOD'); @@ -250,7 +289,7 @@ class ResultState extends MusicBeatSubState var blackTopBar:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/topBarBlack")); blackTopBar.y = -blackTopBar.height; - FlxTween.tween(blackTopBar, {y: 0}, 0.4, {ease: FlxEase.quartOut}); + FlxTween.tween(blackTopBar, {y: 0}, 7/24, {ease: FlxEase.quartOut, startDelay: 3/24}); blackTopBar.zIndex = 1010; add(blackTopBar); @@ -258,7 +297,7 @@ class ResultState extends MusicBeatSubState resultsAnim.visible = false; resultsAnim.zIndex = 1200; add(resultsAnim); - new FlxTimer().start(0.3, _ -> { + new FlxTimer().start(6/24, _ -> { resultsAnim.visible = true; resultsAnim.animation.play("result"); }); @@ -267,7 +306,7 @@ class ResultState extends MusicBeatSubState ratingsPopin.visible = false; ratingsPopin.zIndex = 1200; add(ratingsPopin); - new FlxTimer().start(1.0, _ -> { + new FlxTimer().start(21/24, _ -> { ratingsPopin.visible = true; ratingsPopin.animation.play("idle"); }); @@ -276,23 +315,49 @@ class ResultState extends MusicBeatSubState scorePopin.visible = false; scorePopin.zIndex = 1200; add(scorePopin); - new FlxTimer().start(1.0, _ -> { + new FlxTimer().start(36/24, _ -> { scorePopin.visible = true; scorePopin.animation.play("score"); scorePopin.animation.finishCallback = anim -> { - score.visible = true; - score.animateNumbers(); + }; }); + new FlxTimer().start(37/24, _ -> { + score.visible = true; + score.animateNumbers(); + startRankTallySequence(); + }); + + new FlxTimer().start(rank.getBFDelay(), _ -> { + afterRankTallySequence(); + }); + + new FlxTimer().start(rank.getFlashDelay(), _ -> { + displayRankText(); + }); + highscoreNew.frames = Paths.getSparrowAtlas("resultScreen/highscoreNew"); - highscoreNew.animation.addByPrefix("new", "NEW HIGHSCORE", 24); + highscoreNew.animation.addByPrefix("new", "highscoreAnim0", 24, false); highscoreNew.visible = false; - highscoreNew.setGraphicSize(Std.int(highscoreNew.width * 0.8)); + //highscoreNew.setGraphicSize(Std.int(highscoreNew.width * 0.8)); highscoreNew.updateHitbox(); highscoreNew.zIndex = 1200; add(highscoreNew); + new FlxTimer().start(rank.getHighscoreDelay(), _ -> { + if (params.isNewHighscore ?? false) + { + highscoreNew.visible = true; + highscoreNew.animation.play("new"); + highscoreNew.animation.finishCallback = _ -> highscoreNew.animation.play("new", true, false, 16); + } + else + { + highscoreNew.visible = false; + } + }); + var hStuf:Int = 50; var ratingGrp:FlxTypedGroup = new FlxTypedGroup(); @@ -310,7 +375,10 @@ class ResultState extends MusicBeatSubState ratingGrp.add(maxCombo); hStuf += 2; - var extraYOffset:Float = 5; + var extraYOffset:Float = 7; + + hStuf += 2; + var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, params.scoreData.tallies.sick, 0xFF89E59E); ratingGrp.add(tallySick); @@ -339,20 +407,17 @@ class ResultState extends MusicBeatSubState }); } - ratingsPopin.animation.finishCallback = anim -> { - startRankTallySequence(); - if (params.isNewHighscore ?? false) - { - highscoreNew.visible = true; - highscoreNew.animation.play("new"); - FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); - } - else - { - highscoreNew.visible = false; - } - }; + // if (params.isNewHighscore ?? false) + // { + // highscoreNew.visible = true; + // highscoreNew.animation.play("new"); + // //FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); + // } + // else + // { + // highscoreNew.visible = false; + // } new FlxTimer().start(rank.getMusicDelay(), _ -> { if (rank.hasMusicIntro()) @@ -392,6 +457,8 @@ class ResultState extends MusicBeatSubState function startRankTallySequence():Void { + bgFlash.visible = true; + FlxTween.tween(bgFlash, {alpha: 0}, 5/24); var clearPercentFloat = (params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100; clearPercentTarget = Math.floor(clearPercentFloat); // Prevent off-by-one errors. @@ -400,8 +467,8 @@ class ResultState extends MusicBeatSubState trace('Clear percent target: ' + clearPercentFloat + ', round: ' + clearPercentTarget); - var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter(FlxG.width / 2 + 300, FlxG.height / 2 - 100, clearPercentLerp); - FlxTween.tween(clearPercentCounter, {curNumber: clearPercentTarget}, 1.5, + var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter(FlxG.width / 2 + 190, FlxG.height / 2 - 70, clearPercentLerp); + FlxTween.tween(clearPercentCounter, {curNumber: clearPercentTarget}, 58/24, { ease: FlxEase.quartOut, onUpdate: _ -> { @@ -416,10 +483,6 @@ class ResultState extends MusicBeatSubState // Play confirm sound. FunkinSound.playOnce(Paths.sound('confirmMenu')); - // Flash background. - bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 0.4); - // Just to be sure that the lerp didn't mess things up. clearPercentCounter.curNumber = clearPercentTarget; @@ -428,7 +491,7 @@ class ResultState extends MusicBeatSubState clearPercentCounter.flash(false); }); - displayRankText(); + //displayRankText(); // previously 2.0 seconds new FlxTimer().start(0.25, _ -> { @@ -441,7 +504,7 @@ class ResultState extends MusicBeatSubState } }); - afterRankTallySequence(); + //afterRankTallySequence(); }); } }); @@ -466,7 +529,6 @@ class ResultState extends MusicBeatSubState { highscoreNew.visible = true; highscoreNew.animation.play("new"); - FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); } else { @@ -480,27 +542,36 @@ class ResultState extends MusicBeatSubState function displayRankText():Void { + bgFlash.visible = true; + bgFlash.alpha = 1; + FlxTween.tween(bgFlash, {alpha: 0}, 14/24); + var rankTextVert:FlxBackdrop = new FlxBackdrop(Paths.image(rank.getVerTextAsset()), Y, 0, 30); - rankTextVert.x = FlxG.width - 64; + rankTextVert.x = FlxG.width - 44; rankTextVert.y = 100; rankTextVert.zIndex = 990; add(rankTextVert); - // Scrolling. - rankTextVert.velocity.y = -50; + FlxFlicker.flicker(rankTextVert, 2/24 * 3, 2/24, true); - for (i in 0...10) + // Scrolling. + new FlxTimer().start(30/24, _ -> { + rankTextVert.velocity.y = -80; + }); + + + for (i in 0...12) { var rankTextBack:FlxBackdrop = new FlxBackdrop(Paths.image(rank.getHorTextAsset()), X, 10, 0); rankTextBack.x = FlxG.width / 2 - 320; - rankTextBack.y = 50 + (150 * i / 2) + 10; + rankTextBack.y = 50 + (135 * i / 2) + 10; // rankTextBack.angle = -3.8; rankTextBack.zIndex = 100; rankTextBack.cameras = [cameraScroll]; add(rankTextBack); // Scrolling. - rankTextBack.velocity.x = (i % 2 == 0) ? -10.0 : 10.0; + rankTextBack.velocity.x = (i % 2 == 0) ? -7.0 : 7.0; } refresh(); @@ -508,6 +579,7 @@ class ResultState extends MusicBeatSubState function afterRankTallySequence():Void { + showSmallClearPercent(); switch (rank) @@ -522,6 +594,17 @@ class ResultState extends MusicBeatSubState bfPerfect.visible = true; bfPerfect.playAnimation(''); } + new FlxTimer().start(106 / 24, _ -> { + if (heartsPerfect == null) + { + trace("Could not build heartsPerfect animation!"); + } + else + { + heartsPerfect.visible = true; + heartsPerfect.playAnimation(''); + } + }); case EXCELLENT: if (bfExcellent == null) { @@ -530,7 +613,7 @@ class ResultState extends MusicBeatSubState else { bfExcellent.visible = true; - bfExcellent.playAnimation('Intro'); + bfExcellent.playAnimation(''); } case GREAT: if (bfGreat == null) @@ -540,8 +623,20 @@ class ResultState extends MusicBeatSubState else { bfGreat.visible = true; - bfGreat.playAnimation('Intro'); + bfGreat.playAnimation(''); } + + new FlxTimer().start(6 / 24, _ -> { + if (gfGreat == null) + { + trace("Could not build GREAT animation for gf!"); + } + else + { + gfGreat.visible = true; + gfGreat.playAnimation(''); + } + }); case SHIT: if (bfShit == null) { @@ -627,7 +722,9 @@ class ResultState extends MusicBeatSubState refresh(); } - movingSongStuff = true; + new FlxTimer().start(2.5, _ -> { + movingSongStuff = true; + }); } var movingSongStuff:Bool = false; @@ -647,6 +744,79 @@ class ResultState extends MusicBeatSubState override function update(elapsed:Float):Void { + // if(FlxG.keys.justPressed.R){ + // FlxG.switchState(() -> new funkin.play.ResultState( + // { + // storyMode: false, + // title: "Cum Song Erect by Kawai Sprite", + // songId: "cum", + // difficultyId: "nightmare", + // isNewHighscore: true, + // scoreData: + // { + // score: 1_234_567, + // tallies: + // { + // sick: 200, + // good: 0, + // bad: 0, + // shit: 0, + // missed: 0, + // combo: 0, + // maxCombo: 69, + // totalNotesHit: 200, + // totalNotes: 200 // 0, + // } + // }, + // })); + // } + + // if(heartsPerfect != null){ + // if (FlxG.keys.justPressed.I) + // { + // heartsPerfect.y -= 1; + // trace(heartsPerfect.x, heartsPerfect.y); + // } + // if (FlxG.keys.justPressed.J) + // { + // heartsPerfect.x -= 1; + // trace(heartsPerfect.x, heartsPerfect.y); + // } + // if (FlxG.keys.justPressed.L) + // { + // heartsPerfect.x += 1; + // trace(heartsPerfect.x, heartsPerfect.y); + // } + // if (FlxG.keys.justPressed.K) + // { + // heartsPerfect.y += 1; + // trace(heartsPerfect.x, heartsPerfect.y); + // } + // } + + // if(bfGreat != null){ + // if (FlxG.keys.justPressed.W) + // { + // bfGreat.y -= 1; + // trace(bfGreat.x, bfGreat.y); + // } + // if (FlxG.keys.justPressed.A) + // { + // bfGreat.x -= 1; + // trace(bfGreat.x, bfGreat.y); + // } + // if (FlxG.keys.justPressed.D) + // { + // bfGreat.x += 1; + // trace(bfGreat.x, bfGreat.y); + // } + // if (FlxG.keys.justPressed.S) + // { + // bfGreat.y += 1; + // trace(bfGreat.x, bfGreat.y); + // } + // } + // maskShaderSongName.swagSprX = songName.x; maskShaderDifficulty.swagSprX = difficulty.x; diff --git a/source/funkin/play/scoring/Scoring.hx b/source/funkin/play/scoring/Scoring.hx index 6155ec87..04bd81cf 100644 --- a/source/funkin/play/scoring/Scoring.hx +++ b/source/funkin/play/scoring/Scoring.hx @@ -403,9 +403,75 @@ enum abstract ScoringRank(String) { case PERFECT_GOLD | PERFECT: // return 2.5; - return 5.0; + return 95/24; case EXCELLENT: - return 1.75; + return 0; + case GREAT: + return 5/24; + case GOOD: + return 3/24; + case SHIT: + return 2/24; + default: + return 3.5; + } + } + + public function getBFDelay():Float + { + switch (abstract) + { + case PERFECT_GOLD | PERFECT: + // return 2.5; + return 95/24; + case EXCELLENT: + return 97/24; + case GREAT: + return 95/24; + case GOOD: + return 95/24; + case SHIT: + return 95/24; + default: + return 3.5; + } + } + + public function getFlashDelay():Float + { + switch (abstract) + { + case PERFECT_GOLD | PERFECT: + // return 2.5; + return 129/24; + case EXCELLENT: + return 122/24; + case GREAT: + return 109/24; + case GOOD: + return 107/24; + case SHIT: + return 186/24; + default: + return 3.5; + } + } + + public function getHighscoreDelay():Float + { + switch (abstract) + { + case PERFECT_GOLD | PERFECT: + // return 2.5; + return 140/24; + case EXCELLENT: + return 140/24; + case GREAT: + return 129/24; + case GOOD: + return 127/24; + case SHIT: + return 207/24; default: return 3.5; } From b8920effdcae5b2155a5a9a25e365dd500f9c705 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sat, 1 Jun 2024 01:17:58 +0100 Subject: [PATCH 069/131] assets submod.. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 7a0d92d3..de73a8ec 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 7a0d92d3007de42c452b2ea97a917d8c8d114ee7 +Subproject commit de73a8ec8b7462beedca5c2eb539aea38d4c7712 From fd28c91e75b949976bc074d0cd1d0cde5c97b6f4 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 21:21:46 -0400 Subject: [PATCH 070/131] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 7a0d92d3..59d37621 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 7a0d92d3007de42c452b2ea97a917d8c8d114ee7 +Subproject commit 59d376218d288ef3001de6ef78b8d6d7c5f52842 From 12acdcd9d9cb4cf1a65e5598f421ecca962f33a3 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 21:55:27 -0400 Subject: [PATCH 071/131] Fix a Results->Freeplay crash --- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 192c6e3c..1bde9266 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -868,7 +868,7 @@ class FreeplayState extends MusicBeatSubState FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1); - grpCapsules.members[curSelected].blurredRanking.animation.play(grpCapsules.members[curSelected].blurredRanking.animation.curAnim.name, true); + grpCapsules.members[curSelected].blurredRanking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true); FlxTween.tween(grpCapsules.members[curSelected].blurredRanking, {"scale.x": 1, "scale.y": 1}, 0.1); new FlxTimer().start(0.1, _ -> { From 6851edc64b89ce960d34975af1cf2ce6699e5996 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 21:55:33 -0400 Subject: [PATCH 072/131] Add new charts --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 59d37621..0e5a66cb 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 59d376218d288ef3001de6ef78b8d6d7c5f52842 +Subproject commit 0e5a66cb15229fde2c65503ba1267dfc7b4640b5 From e4eb9a7dc90f40ef667d78c027daecf58832819a Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 1 Jun 2024 16:23:22 -0400 Subject: [PATCH 073/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 0e5a66cb..3bfa4e3d 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e5a66cb15229fde2c65503ba1267dfc7b4640b5 +Subproject commit 3bfa4e3da87713ea651f60d4f898c283e5d86093 From bd7875e86a9a3aabe11d9e6679579540ac011189 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 1 Jun 2024 17:13:07 -0400 Subject: [PATCH 074/131] fix rank icons appearing when they shouldn't be --- source/funkin/play/scoring/Scoring.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/funkin/play/scoring/Scoring.hx b/source/funkin/play/scoring/Scoring.hx index 6155ec87..a6d92454 100644 --- a/source/funkin/play/scoring/Scoring.hx +++ b/source/funkin/play/scoring/Scoring.hx @@ -351,6 +351,9 @@ class Scoring { if (scoreData == null) return null; + // we can return null here, meaning that the player hasn't actually played and finished the song (thus has no data) + if (scoreData.tallies.totalNotes == 0) return null; + // Perfect (Platinum) is a Sick Full Clear var isPerfectGold = scoreData.tallies.sick == scoreData.tallies.totalNotes; if (isPerfectGold) return ScoringRank.PERFECT_GOLD; From 63bd6f2ace9c093133f1c7e1c02de60ad969aa4a Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sun, 2 Jun 2024 00:25:52 +0100 Subject: [PATCH 075/131] sparks nd more fixes.. i think --- source/funkin/play/ResultState.hx | 9 +- source/funkin/ui/freeplay/FreeplayState.hx | 194 +++++++++++++++------ source/funkin/ui/freeplay/SongMenuItem.hx | 15 ++ 3 files changed, 164 insertions(+), 54 deletions(-) diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 1ad19b41..d38731e1 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -364,7 +364,7 @@ class ResultState extends MusicBeatSubState rankBg.zIndex = 99999; add(rankBg); - rankBg.alpha = 0; + rankBg.alpha = 0; refresh(); @@ -665,8 +665,7 @@ class ResultState extends MusicBeatSubState else { var rigged:Bool = true; - if (rank > Scoring.calculateRank(params?.prevScoreData)) - //if (rigged) + if (rank > Scoring.calculateRank(params?.prevScoreData)) // if (rigged) { trace('THE RANK IS Higher.....'); @@ -682,7 +681,8 @@ class ResultState extends MusicBeatSubState oldRank: Scoring.calculateRank(params?.prevScoreData), newRank: rank, songId: params.songId, - difficultyId: params.difficultyId + difficultyId: params.difficultyId, + playRankAnim: true } } })); @@ -698,6 +698,7 @@ class ResultState extends MusicBeatSubState fromResults: { oldRank: null, + playRankAnim: false, newRank: rank, songId: params.songId, difficultyId: params.difficultyId diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 186c84c3..e1d8eb81 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -6,6 +6,7 @@ import flixel.addons.ui.FlxInputText; import flixel.FlxCamera; import flixel.FlxSprite; import flixel.group.FlxGroup; +import funkin.graphics.shaders.GaussianBlurShader; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.input.touch.FlxTouch; @@ -45,6 +46,7 @@ import funkin.util.MathUtil; import lime.utils.Assets; import flixel.tweens.misc.ShakeTween; import funkin.effects.IntervalShake; +import funkin.ui.freeplay.SongMenuItem.FreeplayRank; /** * Parameters used to initialize the FreeplayState. @@ -66,6 +68,11 @@ typedef FromResultsParams = */ var ?oldRank:ScoringRank; + /** + * Whether or not to play the rank animation on returning to freeplay. + */ + var playRankAnim:Bool; + /** * The new rank the song has. */ @@ -201,7 +208,8 @@ class FreeplayState extends MusicBeatSubState fromResultsParams = params?.fromResults; - if(fromResultsParams?.oldRank != null){ + if (fromResultsParams?.playRankAnim == true) + { prepForNewRank = true; } @@ -244,10 +252,10 @@ class FreeplayState extends MusicBeatSubState if (prepForNewRank == false) { FunkinSound.playMusic('freakyMenu', - { - overrideExisting: true, - restartTrack: false - }); + { + overrideExisting: true, + restartTrack: false + }); } // Add a null entry that represents the RANDOM option @@ -837,6 +845,9 @@ class FreeplayState extends MusicBeatSubState return songsToFilter; } + var sparks:FlxSprite; + var sparksADD:FlxSprite; + function rankAnimStart(fromResults:Null):Void { busy = true; @@ -848,6 +859,49 @@ class FreeplayState extends MusicBeatSubState FlxG.sound.music.volume = 0; rankBg.alpha = 1; + if (fromResults?.oldRank != null) + { + grpCapsules.members[curSelected].fakeRanking.rank = fromResults.oldRank; + grpCapsules.members[curSelected].fakeBlurredRanking.rank = fromResults.oldRank; + + sparks = new FlxSprite(0, 0); + sparks.frames = Paths.getSparrowAtlas('freeplay/sparks'); + sparks.animation.addByPrefix('sparks', 'sparks', 24, false); + sparks.visible = false; + sparks.blend = BlendMode.ADD; + sparks.setPosition(517, 134); + sparks.scale.set(0.5, 0.5); + add(sparks); + sparks.cameras = [rankCamera]; + + sparksADD = new FlxSprite(0, 0); + sparksADD.visible = false; + sparksADD.frames = Paths.getSparrowAtlas('freeplay/sparksadd'); + sparksADD.animation.addByPrefix('sparks add', 'sparks add', 24, false); + sparksADD.setPosition(498, 116); + sparksADD.blend = BlendMode.ADD; + sparksADD.scale.set(0.5, 0.5); + add(sparksADD); + sparksADD.cameras = [rankCamera]; + + switch (fromResults.oldRank) + { + case SHIT: + sparksADD.color = 0xFF6044FF; + case GOOD: + sparksADD.color = 0xFFEF8764; + case GREAT: + sparksADD.color = 0xFFEAF6FF; + case EXCELLENT: + sparksADD.color = 0xFFFDCB42; + case PERFECT: + sparksADD.color = 0xFFFF58B4; + case PERFECT_GOLD: + sparksADD.color = 0xFFFFB619; + } + // sparksADD.color = sparks.color; + } + grpCapsules.members[curSelected].doLerp = false; // originalPos.x = grpCapsules.members[curSelected].x; @@ -857,8 +911,8 @@ class FreeplayState extends MusicBeatSubState originalPos.y = 235.6; trace(originalPos); - grpCapsules.members[curSelected].ranking.alpha = 0; - grpCapsules.members[curSelected].blurredRanking.alpha = 0; + grpCapsules.members[curSelected].ranking.visible = false; + grpCapsules.members[curSelected].blurredRanking.visible = false; rankCamera.zoom = 1.85; FlxTween.tween(rankCamera, {"zoom": 1.8}, 0.6, {ease: FlxEase.sineIn}); @@ -880,9 +934,8 @@ class FreeplayState extends MusicBeatSubState function rankDisplayNew(fromResults:Null):Void { - grpCapsules.members[curSelected].ranking.alpha = 1; - grpCapsules.members[curSelected].blurredRanking.alpha = 1; - + grpCapsules.members[curSelected].ranking.visible = true; + grpCapsules.members[curSelected].blurredRanking.visible = true; grpCapsules.members[curSelected].ranking.scale.set(20, 20); grpCapsules.members[curSelected].blurredRanking.scale.set(20, 20); @@ -895,7 +948,23 @@ class FreeplayState extends MusicBeatSubState FlxTween.tween(grpCapsules.members[curSelected].blurredRanking, {"scale.x": 1, "scale.y": 1}, 0.1); new FlxTimer().start(0.1, _ -> { - trace(grpCapsules.members[curSelected].ranking.rank); + // trace(grpCapsules.members[curSelected].ranking.rank); + if (fromResults?.oldRank != null) + { + grpCapsules.members[curSelected].fakeRanking.visible = false; + grpCapsules.members[curSelected].fakeBlurredRanking.visible = false; + + sparks.visible = true; + sparksADD.visible = true; + sparks.animation.play('sparks', true); + sparksADD.animation.play('sparks add', true); + + sparks.animation.finishCallback = anim -> { + sparks.visible = false; + sparksADD.visible = false; + }; + } + switch (fromResultsParams?.newRank) { case SHIT: @@ -1053,10 +1122,10 @@ class FreeplayState extends MusicBeatSubState // dj.fistPump(); prepForNewRank = false; FunkinSound.playMusic('freakyMenu', - { - overrideExisting: true, - restartTrack: false - }); + { + overrideExisting: true, + restartTrack: false + }); FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); }); } @@ -1092,35 +1161,56 @@ class FreeplayState extends MusicBeatSubState rankAnimStart(fromResultsParams); } - if (FlxG.keys.justPressed.H) - { - rankDisplayNew(fromResultsParams); - } + // if (FlxG.keys.justPressed.H) + // { + // rankDisplayNew(fromResultsParams); + // } + + // if (FlxG.keys.justPressed.G) + // { + // rankAnimSlam(fromResultsParams); + // } if (FlxG.keys.justPressed.G) { - rankAnimSlam(fromResultsParams); + sparks.y -= 2; + trace(sparks.x, sparks.y); + } + if (FlxG.keys.justPressed.V) + { + sparks.x -= 2; + trace(sparks.x, sparks.y); + } + if (FlxG.keys.justPressed.N) + { + sparks.x += 2; + trace(sparks.x, sparks.y); + } + if (FlxG.keys.justPressed.B) + { + sparks.y += 2; + trace(sparks.x, sparks.y); } if (FlxG.keys.justPressed.I) { - confirmTextGlow.y -= 1; - trace(confirmTextGlow.x, confirmTextGlow.y); + sparksADD.y -= 2; + trace(sparksADD.x, sparksADD.y); } if (FlxG.keys.justPressed.J) { - confirmTextGlow.x -= 1; - trace(confirmTextGlow.x, confirmTextGlow.y); + sparksADD.x -= 2; + trace(sparksADD.x, sparksADD.y); } if (FlxG.keys.justPressed.L) { - confirmTextGlow.x += 1; - trace(confirmTextGlow.x, confirmTextGlow.y); + sparksADD.x += 2; + trace(sparksADD.x, sparksADD.y); } if (FlxG.keys.justPressed.K) { - confirmTextGlow.y += 1; - trace(confirmTextGlow.x, confirmTextGlow.y); + sparksADD.y += 2; + trace(sparksADD.x, sparksADD.y); } #end @@ -1758,26 +1848,27 @@ class FreeplayState extends MusicBeatSubState } else { - if(prepForNewRank == false){ - var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; - // TODO: Stream the instrumental of the selected song? - FunkinSound.playMusic(daSongCapsule.songData.songId, - { - startingVolume: 0.0, - overrideExisting: true, - restartTrack: false, - pathsFunction: INST, - suffix: potentiallyErect, - partialParams: - { - loadPartial: true, - start: 0, - end: 0.1 - }, - onLoad: function() { - FlxG.sound.music.fadeIn(2, 0, 0.4); - } - }); + if (prepForNewRank == false) + { + var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; + // TODO: Stream the instrumental of the selected song? + FunkinSound.playMusic(daSongCapsule.songData.songId, + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false, + pathsFunction: INST, + suffix: potentiallyErect, + partialParams: + { + loadPartial: true, + start: 0, + end: 0.1 + }, + onLoad: function() { + FlxG.sound.music.fadeIn(2, 0, 0.4); + } + }); } } grpCapsules.members[curSelected].selected = true; @@ -1791,9 +1882,12 @@ class FreeplayState extends MusicBeatSubState public static function build(?params:FreeplayStateParams, ?stickers:StickerSubState):MusicBeatState { var result:MainMenuState; - if(params?.fromResults.oldRank != null){ + if (params?.fromResults.playRankAnim == true) + { result = new MainMenuState(true); - }else{ + } + else + { result = new MainMenuState(false); } diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index b52032bc..3af75c10 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -39,9 +39,13 @@ class SongMenuItem extends FlxSpriteGroup public var songText:CapsuleText; public var favIcon:FlxSprite; + public var ranking:FreeplayRank; public var blurredRanking:FreeplayRank; + public var fakeRanking:FreeplayRank; + public var fakeBlurredRanking:FreeplayRank; + var ranks:Array = ["fail", "average", "great", "excellent", "perfect", "perfectsick"]; public var targetPos:FlxPoint = new FlxPoint(); @@ -131,12 +135,23 @@ class SongMenuItem extends FlxSpriteGroup // doesn't get added, simply is here to help with visibility of things for the pop in! grpHide = new FlxGroup(); + fakeRanking = new FreeplayRank(420, 41); + add(fakeRanking); + + fakeBlurredRanking = new FreeplayRank(fakeRanking.x, fakeRanking.y); + fakeBlurredRanking.shader = new GaussianBlurShader(1); + add(fakeBlurredRanking); + + fakeRanking.visible = false; + fakeBlurredRanking.visible = false; + ranking = new FreeplayRank(420, 41); add(ranking); blurredRanking = new FreeplayRank(ranking.x, ranking.y); blurredRanking.shader = new GaussianBlurShader(1); add(blurredRanking); + // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); // ranking.scale.x = ranking.scale.y = realScaled; // ranking.alpha = 0.75; From b96fa51045f4cae5fa889eade75ac1f1c676034a Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Sun, 2 Jun 2024 00:26:13 +0100 Subject: [PATCH 076/131] assets submod!! --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index d64939d8..ad8a0a28 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit d64939d866c70a831b76ed78930782b66871dcc2 +Subproject commit ad8a0a28addb3153c01bca2f8a2fdea05c5ac9ea From 8248cffbafb1621b5c2811f01a02ee62bd3b48ee Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 1 Jun 2024 20:36:14 -0400 Subject: [PATCH 077/131] small bool cleanings, and maybe fixes --- source/funkin/ui/freeplay/FreeplayState.hx | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index e1d8eb81..e97ab391 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1121,12 +1121,6 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(2, _ -> { // dj.fistPump(); prepForNewRank = false; - FunkinSound.playMusic('freakyMenu', - { - overrideExisting: true, - restartTrack: false - }); - FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); }); } @@ -1527,6 +1521,7 @@ class FreeplayState extends MusicBeatSubState overrideExisting: true, restartTrack: false }); + FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); close(); } else @@ -1842,13 +1837,13 @@ class FreeplayState extends MusicBeatSubState { startingVolume: 0.0, overrideExisting: true, - restartTrack: true + restartTrack: false }); FlxG.sound.music.fadeIn(2, 0, 0.8); } else { - if (prepForNewRank == false) + if (!prepForNewRank) { var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; // TODO: Stream the instrumental of the selected song? @@ -1882,14 +1877,9 @@ class FreeplayState extends MusicBeatSubState public static function build(?params:FreeplayStateParams, ?stickers:StickerSubState):MusicBeatState { var result:MainMenuState; - if (params?.fromResults.playRankAnim == true) - { - result = new MainMenuState(true); - } + if (params?.fromResults.playRankAnim) result = new MainMenuState(true); else - { result = new MainMenuState(false); - } result.openSubState(new FreeplayState(params, stickers)); result.persistentUpdate = false; From 7aee1f900af2d19df18252a72eb382326b878c2f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 31 May 2024 21:55:27 -0400 Subject: [PATCH 078/131] Fix a Results->Freeplay crash --- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index e97ab391..0dd520ee 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -944,7 +944,7 @@ class FreeplayState extends MusicBeatSubState FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1); - grpCapsules.members[curSelected].blurredRanking.animation.play(grpCapsules.members[curSelected].blurredRanking.animation.curAnim.name, true); + grpCapsules.members[curSelected].blurredRanking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true); FlxTween.tween(grpCapsules.members[curSelected].blurredRanking, {"scale.x": 1, "scale.y": 1}, 0.1); new FlxTimer().start(0.1, _ -> { From 7c6c51ea71d8c8790a3ba742e0b7b5724ad33197 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 1 Jun 2024 22:36:47 -0400 Subject: [PATCH 079/131] results dupe fix --- source/funkin/ui/freeplay/FreeplayState.hx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 6441c9cd..218ecc2a 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -712,12 +712,6 @@ class FreeplayState extends MusicBeatSubState // If curSelected is 0, the result will be null and fall back to the rememberedSongId. rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId ?? rememberedSongId; - if (fromResultsParams != null) - { - rememberedSongId = fromResultsParams.songId; - rememberedDifficulty = fromResultsParams.difficultyId; - } - for (cap in grpCapsules.members) { cap.songText.resetText(); @@ -828,6 +822,14 @@ class FreeplayState extends MusicBeatSubState { busy = true; + if (fromResults != null) + { + rememberedSongId = fromResults.songId; + rememberedDifficulty = fromResults.difficultyId; + changeSelection(); + changeDiff(); + } + dj.fistPump(); // rankCamera.fade(FlxColor.BLACK, 0.5, true); rankCamera.fade(0xFF000000, 0.5, true, null, true); From 51a44d481056b5846ed23c97af5f6547ff99ae76 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sat, 1 Jun 2024 23:36:57 -0400 Subject: [PATCH 080/131] persistent draw false for results screen (fixes FUNK-256) --- source/funkin/play/PlayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 478a1326..af3281c4 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -3144,7 +3144,7 @@ class PlayState extends MusicBeatSubState }, isNewHighscore: isNewHighscore }); - res.camera = camHUD; + this.persistentDraw = false; openSubState(res); } From 08f3b1d95b99ce84907fcf74bc12a68c699dc8a8 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sun, 2 Jun 2024 00:15:10 -0400 Subject: [PATCH 081/131] anim fixes on results --- source/funkin/play/ResultState.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 8b8c0aea..35976c35 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -123,6 +123,7 @@ class ResultState extends MusicBeatSubState FlxG.cameras.add(cameraEverything, false); FlxG.cameras.setDefaultDrawTarget(cameraEverything, true); + this.camera = cameraEverything; // Reset the camera zoom on the results screen. FlxG.camera.zoom = 1.0; From f961ac8e4e55e4d9b9f4250b6c123869a6d1a96a Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sun, 2 Jun 2024 02:11:06 -0400 Subject: [PATCH 082/131] Actually fix a crash bug on Freeplay menu when selecting a mod --- hmm.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hmm.json b/hmm.json index fe4e56dd..f94b662a 100644 --- a/hmm.json +++ b/hmm.json @@ -1,12 +1,5 @@ { "dependencies": [ - { - "name": "FlxPartialSound", - "type": "git", - "dir": null, - "ref": "44aa7eb", - "url": "https://github.com/FunkinCrew/FlxPartialSound.git" - }, { "name": "discord_rpc", "type": "git", @@ -47,6 +40,13 @@ "ref": "17e0d59fdbc2b6283a5c0e4df41f1c7f27b71c49", "url": "https://github.com/FunkinCrew/flxanimate" }, + { + "name": "FlxPartialSound", + "type": "git", + "dir": null, + "ref": "f986332ba5ab02abd386ce662578baf04904604a", + "url": "https://github.com/FunkinCrew/FlxPartialSound.git" + }, { "name": "format", "type": "haxelib", From 75621435ea870d80532a66cbf13f60bd361811e3 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Sun, 2 Jun 2024 02:53:07 -0400 Subject: [PATCH 083/131] lil more polish to fav icon + clipping --- source/funkin/ui/freeplay/FreeplayState.hx | 11 ++++++----- source/funkin/ui/freeplay/SongMenuItem.hx | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index d3471eeb..494bc20f 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -655,7 +655,7 @@ class FreeplayState extends MusicBeatSubState cardGlow.visible = true; FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut}); - if (prepForNewRank == true) + if (prepForNewRank) { rankAnimStart(fromResultsParams); } @@ -686,7 +686,7 @@ class FreeplayState extends MusicBeatSubState rankBg.cameras = [rankCamera]; rankBg.alpha = 0; - if (prepForNewRank == true) + if (prepForNewRank) { rankCamera.fade(0xFF000000, 0, false, null, true); } @@ -782,10 +782,8 @@ class FreeplayState extends MusicBeatSubState funnyMenu.hsvShader = hsvShader; funnyMenu.newText.animation.curAnim.curFrame = 45 - ((i * 4) % 45); - - funnyMenu.forcePosition(); - funnyMenu.checkClip(); + funnyMenu.forcePosition(); grpCapsules.add(funnyMenu); } @@ -1223,6 +1221,8 @@ class FreeplayState extends MusicBeatSubState grpCapsules.members[realShit].favIcon.visible = true; grpCapsules.members[realShit].favIcon.animation.play('fav'); FunkinSound.playOnce(Paths.sound('fav'), 1); + grpCapsules.members[realShit].checkClip(); + grpCapsules.members[realShit].selected = grpCapsules.members[realShit].selected; // set selected again, so it can run it's getter function to initialize movement busy = true; grpCapsules.members[realShit].doLerp = false; @@ -1244,6 +1244,7 @@ class FreeplayState extends MusicBeatSubState FunkinSound.playOnce(Paths.sound('unfav'), 1); new FlxTimer().start(0.2, _ -> { grpCapsules.members[realShit].favIcon.visible = false; + grpCapsules.members[realShit].checkClip(); }); busy = true; diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index 41010f0b..b9fef5a7 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -266,7 +266,7 @@ class SongMenuItem extends FlxSpriteGroup var clipType:Int = 0; if (ranking.visible == true) clipType += 1; - if (favIcon.visible == true) clipType += 1; + if (favIcon.visible == true) clipType = 2; switch (clipType) { case 2: From 6596c47f473d935ca135b1e66c384d52007755b8 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 3 Jun 2024 14:03:30 -0400 Subject: [PATCH 084/131] fabs --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index d9ea5ebe..f7c418c5 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit d9ea5ebe5e4db8584a8b1e1e16820b4d1527794c +Subproject commit f7c418c52f38769daf56521ee801df699ae5435b From e12a48b6fc2721086fa54b6deb3d7cd08130ae2b Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 3 Jun 2024 18:18:33 -0400 Subject: [PATCH 085/131] fabs code stuff and difficulty fixin --- assets | 2 +- source/funkin/play/ResultState.hx | 123 ++++++++++++++---------------- 2 files changed, 59 insertions(+), 66 deletions(-) diff --git a/assets b/assets index f7c418c5..3766c3b6 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit f7c418c52f38769daf56521ee801df699ae5435b +Subproject commit 3766c3b6709f043e63d8eae66887159975891073 diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 1740c037..6f540687 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -143,14 +143,14 @@ class ResultState extends MusicBeatSubState bgFlash.scrollFactor.set(); bgFlash.visible = false; bgFlash.zIndex = 20; - //bgFlash.cameras = [cameraBG]; + // bgFlash.cameras = [cameraBG]; add(bgFlash); // The sound system which falls into place behind the score text. Plays every time! var soundSystem:FlxSprite = FunkinSprite.createSparrow(-15, -180, 'resultScreen/soundSystem'); soundSystem.animation.addByPrefix("idle", "sound system", 24, false); soundSystem.visible = false; - new FlxTimer().start(8/24, _ -> { + new FlxTimer().start(8 / 24, _ -> { soundSystem.animation.play("idle"); soundSystem.visible = true; }); @@ -168,13 +168,12 @@ class ResultState extends MusicBeatSubState heartsPerfect.anim.onComplete = () -> { if (heartsPerfect != null) { - //bfPerfect.anim.curFrame = 137; + // bfPerfect.anim.curFrame = 137; heartsPerfect.anim.curFrame = 43; heartsPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! } }; - bfPerfect = new FlxAtlasSprite(1342, 370, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT", "shared")); bfPerfect.visible = false; bfPerfect.zIndex = 500; @@ -183,7 +182,7 @@ class ResultState extends MusicBeatSubState bfPerfect.anim.onComplete = () -> { if (bfPerfect != null) { - //bfPerfect.anim.curFrame = 137; + // bfPerfect.anim.curFrame = 137; bfPerfect.anim.curFrame = 137; bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce! } @@ -203,7 +202,6 @@ class ResultState extends MusicBeatSubState } }; - case GREAT: gfGreat = new FlxAtlasSprite(802, 331, Paths.animateAtlas("resultScreen/results-bf/resultsGREAT/gf", "shared")); gfGreat.visible = false; @@ -273,7 +271,7 @@ class ResultState extends MusicBeatSubState }); } - var diffSpr:String = 'dif${params?.difficultyId ?? 'Normal'}'; + var diffSpr:String = 'diff_${params?.difficultyId ?? 'Normal'}'; difficulty.loadGraphic(Paths.image("resultScreen/" + diffSpr)); add(difficulty); @@ -293,7 +291,7 @@ class ResultState extends MusicBeatSubState var blackTopBar:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/topBarBlack")); blackTopBar.y = -blackTopBar.height; - FlxTween.tween(blackTopBar, {y: 0}, 7/24, {ease: FlxEase.quartOut, startDelay: 3/24}); + FlxTween.tween(blackTopBar, {y: 0}, 7 / 24, {ease: FlxEase.quartOut, startDelay: 3 / 24}); blackTopBar.zIndex = 1010; add(blackTopBar); @@ -301,7 +299,7 @@ class ResultState extends MusicBeatSubState resultsAnim.visible = false; resultsAnim.zIndex = 1200; add(resultsAnim); - new FlxTimer().start(6/24, _ -> { + new FlxTimer().start(6 / 24, _ -> { resultsAnim.visible = true; resultsAnim.animation.play("result"); }); @@ -310,7 +308,7 @@ class ResultState extends MusicBeatSubState ratingsPopin.visible = false; ratingsPopin.zIndex = 1200; add(ratingsPopin); - new FlxTimer().start(21/24, _ -> { + new FlxTimer().start(21 / 24, _ -> { ratingsPopin.visible = true; ratingsPopin.animation.play("idle"); }); @@ -319,15 +317,13 @@ class ResultState extends MusicBeatSubState scorePopin.visible = false; scorePopin.zIndex = 1200; add(scorePopin); - new FlxTimer().start(36/24, _ -> { + new FlxTimer().start(36 / 24, _ -> { scorePopin.visible = true; scorePopin.animation.play("score"); - scorePopin.animation.finishCallback = anim -> { - - }; + scorePopin.animation.finishCallback = anim -> {}; }); - new FlxTimer().start(37/24, _ -> { + new FlxTimer().start(37 / 24, _ -> { score.visible = true; score.animateNumbers(); startRankTallySequence(); @@ -344,22 +340,22 @@ class ResultState extends MusicBeatSubState highscoreNew.frames = Paths.getSparrowAtlas("resultScreen/highscoreNew"); highscoreNew.animation.addByPrefix("new", "highscoreAnim0", 24, false); highscoreNew.visible = false; - //highscoreNew.setGraphicSize(Std.int(highscoreNew.width * 0.8)); + // highscoreNew.setGraphicSize(Std.int(highscoreNew.width * 0.8)); highscoreNew.updateHitbox(); highscoreNew.zIndex = 1200; add(highscoreNew); new FlxTimer().start(rank.getHighscoreDelay(), _ -> { - if (params.isNewHighscore ?? false) - { - highscoreNew.visible = true; - highscoreNew.animation.play("new"); - highscoreNew.animation.finishCallback = _ -> highscoreNew.animation.play("new", true, false, 16); - } - else - { - highscoreNew.visible = false; - } + if (params.isNewHighscore ?? false) + { + highscoreNew.visible = true; + highscoreNew.animation.play("new"); + highscoreNew.animation.finishCallback = _ -> highscoreNew.animation.play("new", true, false, 16); + } + else + { + highscoreNew.visible = false; + } }); var hStuf:Int = 50; @@ -411,17 +407,16 @@ class ResultState extends MusicBeatSubState }); } - - // if (params.isNewHighscore ?? false) - // { - // highscoreNew.visible = true; - // highscoreNew.animation.play("new"); - // //FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); - // } - // else - // { - // highscoreNew.visible = false; - // } + // if (params.isNewHighscore ?? false) + // { + // highscoreNew.visible = true; + // highscoreNew.animation.play("new"); + // //FlxTween.tween(highscoreNew, {y: highscoreNew.y + 10}, 0.8, {ease: FlxEase.quartOut}); + // } + // else + // { + // highscoreNew.visible = false; + // } new FlxTimer().start(rank.getMusicDelay(), _ -> { if (rank.hasMusicIntro()) @@ -468,7 +463,7 @@ class ResultState extends MusicBeatSubState function startRankTallySequence():Void { bgFlash.visible = true; - FlxTween.tween(bgFlash, {alpha: 0}, 5/24); + FlxTween.tween(bgFlash, {alpha: 0}, 5 / 24); var clearPercentFloat = (params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100; clearPercentTarget = Math.floor(clearPercentFloat); // Prevent off-by-one errors. @@ -478,7 +473,7 @@ class ResultState extends MusicBeatSubState trace('Clear percent target: ' + clearPercentFloat + ', round: ' + clearPercentTarget); var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter(FlxG.width / 2 + 190, FlxG.height / 2 - 70, clearPercentLerp); - FlxTween.tween(clearPercentCounter, {curNumber: clearPercentTarget}, 58/24, + FlxTween.tween(clearPercentCounter, {curNumber: clearPercentTarget}, 58 / 24, { ease: FlxEase.quartOut, onUpdate: _ -> { @@ -501,7 +496,7 @@ class ResultState extends MusicBeatSubState clearPercentCounter.flash(false); }); - //displayRankText(); + // displayRankText(); // previously 2.0 seconds new FlxTimer().start(0.25, _ -> { @@ -514,7 +509,7 @@ class ResultState extends MusicBeatSubState } }); - //afterRankTallySequence(); + // afterRankTallySequence(); }); } }); @@ -554,7 +549,7 @@ class ResultState extends MusicBeatSubState { bgFlash.visible = true; bgFlash.alpha = 1; - FlxTween.tween(bgFlash, {alpha: 0}, 14/24); + FlxTween.tween(bgFlash, {alpha: 0}, 14 / 24); var rankTextVert:FlxBackdrop = new FlxBackdrop(Paths.image(rank.getVerTextAsset()), Y, 0, 30); rankTextVert.x = FlxG.width - 44; @@ -562,14 +557,13 @@ class ResultState extends MusicBeatSubState rankTextVert.zIndex = 990; add(rankTextVert); - FlxFlicker.flicker(rankTextVert, 2/24 * 3, 2/24, true); + FlxFlicker.flicker(rankTextVert, 2 / 24 * 3, 2 / 24, true); // Scrolling. - new FlxTimer().start(30/24, _ -> { - rankTextVert.velocity.y = -80; + new FlxTimer().start(30 / 24, _ -> { + rankTextVert.velocity.y = -80; }); - for (i in 0...12) { var rankTextBack:FlxBackdrop = new FlxBackdrop(Paths.image(rank.getHorTextAsset()), X, 10, 0); @@ -589,7 +583,6 @@ class ResultState extends MusicBeatSubState function afterRankTallySequence():Void { - showSmallClearPercent(); switch (rank) @@ -605,15 +598,15 @@ class ResultState extends MusicBeatSubState bfPerfect.playAnimation(''); } new FlxTimer().start(106 / 24, _ -> { - if (heartsPerfect == null) - { - trace("Could not build heartsPerfect animation!"); - } - else - { - heartsPerfect.visible = true; - heartsPerfect.playAnimation(''); - } + if (heartsPerfect == null) + { + trace("Could not build heartsPerfect animation!"); + } + else + { + heartsPerfect.visible = true; + heartsPerfect.playAnimation(''); + } }); case EXCELLENT: if (bfExcellent == null) @@ -637,15 +630,15 @@ class ResultState extends MusicBeatSubState } new FlxTimer().start(6 / 24, _ -> { - if (gfGreat == null) - { - trace("Could not build GREAT animation for gf!"); - } - else - { - gfGreat.visible = true; - gfGreat.playAnimation(''); - } + if (gfGreat == null) + { + trace("Could not build GREAT animation for gf!"); + } + else + { + gfGreat.visible = true; + gfGreat.playAnimation(''); + } }); case SHIT: if (bfShit == null) From cd85bcf22264b9527848a2d2963206b898ee8bd2 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Mon, 3 Jun 2024 18:32:46 -0400 Subject: [PATCH 086/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 3766c3b6..1f3e2932 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 3766c3b6709f043e63d8eae66887159975891073 +Subproject commit 1f3e2932ebc3395eb484e364605c233166052868 From bc21f0c6063453e10e102411c7c69018d978c29e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 3 Jun 2024 19:39:37 -0400 Subject: [PATCH 087/131] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 1f3e2932..4039bd01 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 1f3e2932ebc3395eb484e364605c233166052868 +Subproject commit 4039bd018d474994b44317b74cdd724b5f73b749 From c056c7276285b847e4ea969ccb3b38dd23fd60b6 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 4 Jun 2024 14:26:24 -0400 Subject: [PATCH 088/131] Implement advanced save data repair. --- source/funkin/save/Save.hx | 81 +++++++++++++++++++ .../funkin/save/migrator/SaveDataMigrator.hx | 1 + source/funkin/util/VersionUtil.hx | 5 +- 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 7f25a8e0..7634c1f5 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -732,6 +732,87 @@ class Save } } + public static function archiveBadSaveData(data:Dynamic):Void + { + // We want to save this somewhere so we can try to recover it for the user in the future! + + final RECOVERY_SLOT_START = 1000; + + writeToAvailableSlot(RECOVERY_SLOT_START, data); + } + + public static function debug_queryBadSaveData():Void + { + final RECOVERY_SLOT_START = 1000; + final RECOVERY_SLOT_END = 1100; + var firstBadSaveData = querySlotRange(RECOVERY_SLOT_START, RECOVERY_SLOT_END); + if (firstBadSaveData > 0) + { + trace('[SAVE] Found bad save data in slot ${firstBadSaveData}!'); + trace('We should look into recovery...'); + + trace(haxe.Json.stringify(fetchFromSlotRaw(firstBadSaveData))); + } + } + + static function fetchFromSlotRaw(slot:Int):Null + { + var targetSaveData = new FlxSave(); + targetSaveData.bind('$SAVE_NAME${slot}', SAVE_PATH); + if (targetSaveData.isEmpty()) return null; + return targetSaveData.data; + } + + static function writeToAvailableSlot(slot:Int, data:Dynamic):Void + { + trace('[SAVE] Finding slot to write data to (starting with ${slot})...'); + + var targetSaveData = new FlxSave(); + targetSaveData.bind('$SAVE_NAME${slot}', SAVE_PATH); + while (!targetSaveData.isEmpty()) + { + // Keep trying to bind to slots until we find an empty slot. + trace('[SAVE] Slot ${slot} is taken, continuing...'); + slot++; + targetSaveData.bind('$SAVE_NAME${slot}', SAVE_PATH); + } + + trace('[SAVE] Writing data to slot ${slot}...'); + targetSaveData.mergeData(data, true); + + trace('[SAVE] Data written to slot ${slot}!'); + } + + /** + * Return true if the given save slot is not empty. + * @param slot The slot number to check. + * @return Whether the slot is not empty. + */ + static function querySlot(slot:Int):Bool + { + var targetSaveData = new FlxSave(); + targetSaveData.bind('$SAVE_NAME${slot}', SAVE_PATH); + return !targetSaveData.isEmpty(); + } + + /** + * Return true if any of the slots in the given range is not empty. + * @param start The starting slot number to check. + * @param end The ending slot number to check. + * @return The first slot in the range that is not empty, or `-1` if none are. + */ + static function querySlotRange(start:Int, end:Int):Int + { + for (i in start...end) + { + if (querySlot(i)) + { + return i; + } + } + return -1; + } + static function fetchLegacySaveData():Null { trace("[SAVE] Checking for legacy save data..."); diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index 4fa9dd6b..b7d278cc 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -36,6 +36,7 @@ class SaveDataMigrator { var message:String = 'Error migrating save data, expected ${Save.SAVE_DATA_VERSION}.'; lime.app.Application.current.window.alert(message, "Save Data Failure"); + Save.archiveBadSaveData(inputData); trace('[SAVE] ' + message); return new Save(Save.getDefault()); } diff --git a/source/funkin/util/VersionUtil.hx b/source/funkin/util/VersionUtil.hx index 18d7eafa..b84b6634 100644 --- a/source/funkin/util/VersionUtil.hx +++ b/source/funkin/util/VersionUtil.hx @@ -39,13 +39,16 @@ class VersionUtil if (thx.Types.isAnonymousObject(versionData.version)) { // This is bad! versionData.version should be an array! - versionData.version = [versionData.version[0], versionData.version[1], versionData.version[2]]; + trace('[SAVE] Version data repair required! (got ${versionData.version})'); + var fixedVersionData = [versionData.version[0], versionData.version[1], versionData.version[2]]; + versionData.version = fixedVersionData; var fixedVersion:thx.semver.Version = versionData; return fixedVersion; } else { + trace('[SAVE] Version data repair not required (got ${version})'); // No need for repair. return version; } From d4712a8ef7ebc60318e47b6c70faca646a9d0830 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 16:24:24 -0400 Subject: [PATCH 089/131] alphabetical filtering for freeplay non-all sort --- source/funkin/ui/freeplay/FreeplayState.hx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 494bc20f..fe64a1e6 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -804,6 +804,13 @@ class FreeplayState extends MusicBeatSubState */ public function sortSongs(songsToFilter:Array, songFilter:SongFilter):Array { + var filterAlphabetically = function(a:FreeplaySongData, b:FreeplaySongData):Int { + if (a?.songName.toLowerCase() < b?.songName.toLowerCase()) return -1; + else if (a?.songName.toLowerCase() > b?.songName.toLowerCase()) return 1; + else + return 0; + }; + switch (songFilter.filterType) { case REGEXP: @@ -818,6 +825,8 @@ class FreeplayState extends MusicBeatSubState return filterRegexp.match(str.songName); }); + songsToFilter.sort(filterAlphabetically); + case STARTSWITH: // extra note: this is essentially a "search" @@ -832,9 +841,13 @@ class FreeplayState extends MusicBeatSubState if (str == null) return true; // Random return str.isFav; }); + + songsToFilter.sort(filterAlphabetically); + default: // return all on default } + return songsToFilter; } From 29a33c8815a1ca3e33a731f9d8d405a57041f102 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 16:38:21 -0400 Subject: [PATCH 090/131] modifies behaviour of how the difficulty stars appear --- source/funkin/ui/freeplay/AlbumRoll.hx | 7 ++++--- source/funkin/ui/freeplay/DifficultyStars.hx | 11 ++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx index 20cd9137..49c58872 100644 --- a/source/funkin/ui/freeplay/AlbumRoll.hx +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -66,7 +66,7 @@ class AlbumRoll extends FlxSpriteGroup add(newAlbumArt); difficultyStars = new DifficultyStars(140, 39); - difficultyStars.stars.visible = false; + difficultyStars.visible = false; add(difficultyStars); } @@ -149,7 +149,7 @@ class AlbumRoll extends FlxSpriteGroup newAlbumArt.visible = true; newAlbumArt.playAnimation(animNames.get('$albumId-active'), false, false, false); - difficultyStars.stars.visible = false; + difficultyStars.visible = false; new FlxTimer().start(0.75, function(_) { // showTitle(); showStars(); @@ -172,6 +172,7 @@ class AlbumRoll extends FlxSpriteGroup */ public function showStars():Void { - difficultyStars.stars.visible = true; // true; + difficultyStars.visible = true; // true; + difficultyStars.flameCheck(); } } diff --git a/source/funkin/ui/freeplay/DifficultyStars.hx b/source/funkin/ui/freeplay/DifficultyStars.hx index 51526bcb..e7a2b888 100644 --- a/source/funkin/ui/freeplay/DifficultyStars.hx +++ b/source/funkin/ui/freeplay/DifficultyStars.hx @@ -19,7 +19,7 @@ class DifficultyStars extends FlxSpriteGroup public var stars:FlxAtlasSprite; - var flames:FreeplayFlames; + public var flames:FreeplayFlames; var hsvShader:HSVShader; @@ -80,11 +80,16 @@ class DifficultyStars extends FlxSpriteGroup curDifficulty = difficulty - 1; } + flameCheck(); + + return difficulty; + } + + public function flameCheck():Void + { if (difficulty > 10) flames.flameCount = difficulty - 10; else flames.flameCount = 0; - - return difficulty; } function set_curDifficulty(value:Int):Int From 84d4d044d647fa3460ca484526cb3282a0c51930 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 16:47:58 -0400 Subject: [PATCH 091/131] check clip width when text changes --- source/funkin/ui/freeplay/CapsuleText.hx | 20 ++++++++++++++++---- source/funkin/ui/freeplay/SongMenuItem.hx | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/source/funkin/ui/freeplay/CapsuleText.hx b/source/funkin/ui/freeplay/CapsuleText.hx index c3fd51d1..c3bcdb09 100644 --- a/source/funkin/ui/freeplay/CapsuleText.hx +++ b/source/funkin/ui/freeplay/CapsuleText.hx @@ -58,12 +58,24 @@ class CapsuleText extends FlxSpriteGroup function set_clipWidth(value:Int):Int { resetText(); - if (whiteText.width > value) + checkClipWidth(value); + return clipWidth = value; + } + + /** + * Checks if the text if it's too long, and clips if it is + * @param wid + */ + function checkClipWidth(?wid:Int):Void + { + if (wid == null) wid = clipWidth; + + if (whiteText.width > wid) { tooLong = true; - blurredText.clipRect = new FlxRect(0, 0, value, blurredText.height); - whiteText.clipRect = new FlxRect(0, 0, value, whiteText.height); + blurredText.clipRect = new FlxRect(0, 0, wid, blurredText.height); + whiteText.clipRect = new FlxRect(0, 0, wid, whiteText.height); } else { @@ -72,7 +84,6 @@ class CapsuleText extends FlxSpriteGroup blurredText.clipRect = null; whiteText.clipRect = null; } - return clipWidth = value; } function set_text(value:String):String @@ -86,6 +97,7 @@ class CapsuleText extends FlxSpriteGroup blurredText.text = value; whiteText.text = value; + checkClipWidth(); whiteText.textField.filters = [ new openfl.filters.GlowFilter(0x00ccff, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM), // new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW) diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index b9fef5a7..d40809fa 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -326,7 +326,7 @@ class SongMenuItem extends FlxSpriteGroup var evilTrail:FlxTrail; - public function fadeAnim() + public function fadeAnim():Void { impactThing = new FunkinSprite(0, 0); impactThing.frames = capsule.frames; From 6a62f38c33a33c90c224bfc7ecbef0481e29c908 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 16:51:27 -0400 Subject: [PATCH 092/131] quicki fix for incorrect clip tweens --- source/funkin/ui/freeplay/SongMenuItem.hx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index d40809fa..b861bca1 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -671,14 +671,9 @@ class SongMenuItem extends FlxSpriteGroup ranking.alpha = this.selected ? 1 : 0.7; ranking.color = this.selected ? 0xFFFFFFFF : 0xFFAAAAAA; - if (selected) - { - if (songText.tooLong == true) songText.initMove(); - } - else - { - if (songText.tooLong == true) songText.resetText(); - } + if (songText.tooLong) songText.resetText(); + + if (selected && songText.tooLong) songText.initMove(); } } From ae950c738214e20446cc8ded5b163544a5ee0280 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 4 Jun 2024 19:44:00 -0400 Subject: [PATCH 093/131] Finish save data repair (you should be able to transfer your save now) --- CHANGELOG.md | 1 + source/funkin/save/Save.hx | 16 +++++++++------- source/funkin/save/changelog.md | 4 ++++ .../funkin/save/migrator/SaveDataMigrator.hx | 6 +++--- source/funkin/util/VersionUtil.hx | 18 ++++++++++++++++-- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5aefb88..898978ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Senpai (increased the note speed) - Thorns (increased the note speed slightly) - Favorite songs marked in Freeplay are now stored between sessions. +- In the event that the game cannot load your save data, it will now perform a backup before clearing it, so that we can try to repair it in the future. - Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!) - Improved logic for NoteHitScriptEvents, allowing you to view the hit diff and modify whether a note hit is a combo break (thanks nebulazorua!) - Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!) diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 7634c1f5..2ff6b96c 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -16,7 +16,7 @@ import thx.semver.Version; @:nullSafety class Save { - public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.4"; + public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.5"; public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x"; // We load this version's saves from a new save path, to maintain SOME level of backwards compatibility. @@ -56,6 +56,9 @@ class Save if (data == null) this.data = Save.getDefault(); else this.data = data; + + // Make sure the verison number is up to date before we flush. + this.data.version = Save.SAVE_DATA_VERSION; } public static function getDefault():RawSaveData @@ -713,7 +716,6 @@ class Save { trace('[SAVE] Found legacy save data, converting...'); var gameSave = SaveDataMigrator.migrateFromLegacy(legacySaveData); - @:privateAccess FlxG.save.mergeData(gameSave.data, true); } else @@ -725,20 +727,19 @@ class Save } else { - trace('[SAVE] Loaded save data.'); - @:privateAccess + trace('[SAVE] Found existing save data.'); var gameSave = SaveDataMigrator.migrate(FlxG.save.data); FlxG.save.mergeData(gameSave.data, true); } } - public static function archiveBadSaveData(data:Dynamic):Void + public static function archiveBadSaveData(data:Dynamic):Int { // We want to save this somewhere so we can try to recover it for the user in the future! final RECOVERY_SLOT_START = 1000; - writeToAvailableSlot(RECOVERY_SLOT_START, data); + return writeToAvailableSlot(RECOVERY_SLOT_START, data); } public static function debug_queryBadSaveData():Void @@ -763,7 +764,7 @@ class Save return targetSaveData.data; } - static function writeToAvailableSlot(slot:Int, data:Dynamic):Void + static function writeToAvailableSlot(slot:Int, data:Dynamic):Int { trace('[SAVE] Finding slot to write data to (starting with ${slot})...'); @@ -781,6 +782,7 @@ class Save targetSaveData.mergeData(data, true); trace('[SAVE] Data written to slot ${slot}!'); + return slot; } /** diff --git a/source/funkin/save/changelog.md b/source/funkin/save/changelog.md index 7c9094f2..e3038373 100644 --- a/source/funkin/save/changelog.md +++ b/source/funkin/save/changelog.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.5] - 2024-05-21 +### Fixed +- Resolved an issue where HTML5 wouldn't store the semantic version properly, causing the game to fail to load the save. + ## [2.0.4] - 2024-05-21 ### Added - `favoriteSongs:Array` to `Save` diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index b7d278cc..7a929322 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -35,9 +35,9 @@ class SaveDataMigrator else { var message:String = 'Error migrating save data, expected ${Save.SAVE_DATA_VERSION}.'; - lime.app.Application.current.window.alert(message, "Save Data Failure"); - Save.archiveBadSaveData(inputData); - trace('[SAVE] ' + message); + var slot:Int = Save.archiveBadSaveData(inputData); + var fullMessage:String = 'An error occurred migrating your save data.\n${message}\nInvalid data has been moved to save slot ${slot}.'; + lime.app.Application.current.window.alert(fullMessage, "Save Data Failure"); return new Save(Save.getDefault()); } } diff --git a/source/funkin/util/VersionUtil.hx b/source/funkin/util/VersionUtil.hx index b84b6634..832ce008 100644 --- a/source/funkin/util/VersionUtil.hx +++ b/source/funkin/util/VersionUtil.hx @@ -23,6 +23,8 @@ class VersionUtil { try { + var versionRaw:thx.semver.Version.SemVer = version; + trace('${versionRaw} satisfies (${versionRule})? ${version.satisfies(versionRule)}'); return version.satisfies(versionRule); } catch (e) @@ -40,10 +42,22 @@ class VersionUtil { // This is bad! versionData.version should be an array! trace('[SAVE] Version data repair required! (got ${versionData.version})'); - var fixedVersionData = [versionData.version[0], versionData.version[1], versionData.version[2]]; - versionData.version = fixedVersionData; + // Turn the objects back into arrays. + // I'd use DynamicsT.values but IDK if it maintains order + versionData.version = [versionData.version[0], versionData.version[1], versionData.version[2]]; + + // This is so jank but it should work. + var buildData:Dynamic = cast versionData.build; + var buildDataFixed:Array = thx.Dynamics.DynamicsT.values(buildData) + .map(function(d:Dynamic) return StringId(d.toString())); + versionData.build = buildDataFixed; + + var preData:Dynamic = cast versionData.pre; + var preDataFixed:Array = thx.Dynamics.DynamicsT.values(preData).map(function(d:Dynamic) return StringId(d.toString())); + versionData.pre = preDataFixed; var fixedVersion:thx.semver.Version = versionData; + trace('[SAVE] Fixed version: ${fixedVersion}'); return fixedVersion; } else From 97400ed5d8dc8867f7eb4dde01ed7b0832309054 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 22:26:35 -0400 Subject: [PATCH 094/131] santa sounds --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 4039bd01..b7d3772e 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4039bd018d474994b44317b74cdd724b5f73b749 +Subproject commit b7d3772e76ca1d05626201594acb7f4b996d4a80 From f2dd626ed9ab616d6b66d72fb2b399683fd11999 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 22:37:51 -0400 Subject: [PATCH 095/131] rollback viz hmm --- hmm.json | 2 +- source/funkin/audio/visualize/ABotVis.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hmm.json b/hmm.json index e364e405..a1998f51 100644 --- a/hmm.json +++ b/hmm.json @@ -49,7 +49,7 @@ "name": "funkin.vis", "type": "git", "dir": null, - "ref": "38261833590773cb1de34ac5d11e0825696fc340", + "ref": "c6a1e24d48646849ea63563ca45561512c953779", "url": "https://github.com/FunkinCrew/funkVis" }, { diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index 15596318..8ddc4169 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -58,7 +58,7 @@ class ABotVis extends FlxTypedSpriteGroup public function initAnalyzer() { @:privateAccess - analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.01, 30); + analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.1, 30); // analyzer.maxDb = -35; // analyzer.fftN = 2048; } From 8bdaf8f513c9a003f1622123dce1aeeb1d8ebab5 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 22:55:21 -0400 Subject: [PATCH 096/131] web rank sounds --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index b7d3772e..f2202ff9 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit b7d3772e76ca1d05626201594acb7f4b996d4a80 +Subproject commit f2202ff9d920743830cf2b47442040ad80f5ca05 From 66d86a6969b924cba3c17ae5505aea7dbddcec6f Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 23:07:08 -0400 Subject: [PATCH 097/131] 2hot death fix --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index f2202ff9..613365d9 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit f2202ff9d920743830cf2b47442040ad80f5ca05 +Subproject commit 613365d98921346f0502a62d0a5f68fce6d27373 From 50990b15e100a18f2f3d2cd8074e09a8c70e3749 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 23:36:32 -0400 Subject: [PATCH 098/131] heart glow --- source/funkin/ui/freeplay/FreeplayState.hx | 6 ++++++ source/funkin/ui/freeplay/SongMenuItem.hx | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index fe64a1e6..4fc94c2d 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -757,6 +757,7 @@ class FreeplayState extends MusicBeatSubState randomCapsule.alpha = 0; randomCapsule.songText.visible = false; randomCapsule.favIcon.visible = false; + randomCapsule.favIconBlurred.visible = false; randomCapsule.ranking.visible = false; randomCapsule.blurredRanking.visible = false; randomCapsule.initJumpIn(0, force); @@ -779,6 +780,7 @@ class FreeplayState extends MusicBeatSubState funnyMenu.capsule.alpha = 0.5; funnyMenu.songText.visible = false; funnyMenu.favIcon.visible = tempSongs[i].isFav; + funnyMenu.favIconBlurred.visible = tempSongs[i].isFav; funnyMenu.hsvShader = hsvShader; funnyMenu.newText.animation.curAnim.curFrame = 45 - ((i * 4) % 45); @@ -1232,7 +1234,9 @@ class FreeplayState extends MusicBeatSubState if (isFav) { grpCapsules.members[realShit].favIcon.visible = true; + grpCapsules.members[realShit].favIconBlurred.visible = true; grpCapsules.members[realShit].favIcon.animation.play('fav'); + grpCapsules.members[realShit].favIconBlurred.animation.play('fav'); FunkinSound.playOnce(Paths.sound('fav'), 1); grpCapsules.members[realShit].checkClip(); grpCapsules.members[realShit].selected = grpCapsules.members[realShit].selected; // set selected again, so it can run it's getter function to initialize movement @@ -1254,9 +1258,11 @@ class FreeplayState extends MusicBeatSubState else { grpCapsules.members[realShit].favIcon.animation.play('fav', true, true, 9); + grpCapsules.members[realShit].favIconBlurred.animation.play('fav', true, true, 9); FunkinSound.playOnce(Paths.sound('unfav'), 1); new FlxTimer().start(0.2, _ -> { grpCapsules.members[realShit].favIcon.visible = false; + grpCapsules.members[realShit].favIconBlurred.visible = false; grpCapsules.members[realShit].checkClip(); }); diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index b861bca1..fb91fbd1 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -38,6 +38,7 @@ class SongMenuItem extends FlxSpriteGroup public var selected(default, set):Bool; public var songText:CapsuleText; + public var favIconBlurred:FlxSprite; public var favIcon:FlxSprite; public var ranking:FreeplayRank; @@ -190,6 +191,16 @@ class SongMenuItem extends FlxSpriteGroup add(pixelIcon); grpHide.add(pixelIcon); + favIconBlurred = new FlxSprite(380, 40); + favIconBlurred.frames = Paths.getSparrowAtlas('freeplay/favHeart'); + favIconBlurred.animation.addByPrefix('fav', 'favorite heart', 24, false); + favIconBlurred.animation.play('fav'); + favIconBlurred.setGraphicSize(50, 50); + favIconBlurred.blend = BlendMode.ADD; + favIconBlurred.shader = new GaussianBlurShader(1.2); + favIconBlurred.visible = false; + add(favIconBlurred); + favIcon = new FlxSprite(380, 40); favIcon.frames = Paths.getSparrowAtlas('freeplay/favHeart'); favIcon.animation.addByPrefix('fav', 'favorite heart', 24, false); @@ -669,6 +680,8 @@ class SongMenuItem extends FlxSpriteGroup capsule.offset.x = this.selected ? 0 : -5; capsule.animation.play(this.selected ? "selected" : "unselected"); ranking.alpha = this.selected ? 1 : 0.7; + favIcon.alpha = this.selected ? 1 : 0.6; + favIconBlurred.alpha = this.selected ? 1 : 0; ranking.color = this.selected ? 0xFFFFFFFF : 0xFFAAAAAA; if (songText.tooLong) songText.resetText(); From 03bccee0542c363548b9cad25e1cbfd84e6fb0a3 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Tue, 4 Jun 2024 23:39:49 -0400 Subject: [PATCH 099/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 613365d9..efb7a833 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 613365d98921346f0502a62d0a5f68fce6d27373 +Subproject commit efb7a833a78ab9c3bd9fe36bb10a8adc6a87e30b From 5dda95c69baffddfae35f7e5fdf1fdb84661a80f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 5 Jun 2024 00:40:14 -0400 Subject: [PATCH 100/131] Fix some display issues with the clear percent in the results screen. --- source/funkin/InitState.hx | 2 +- .../play/components/ClearPercentCounter.hx | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index c7a08d71..49b15ddf 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -229,7 +229,7 @@ class InitState extends FlxState tallies: { sick: 130, - good: 70, + good: 60, bad: 69, shit: 69, missed: 69, diff --git a/source/funkin/play/components/ClearPercentCounter.hx b/source/funkin/play/components/ClearPercentCounter.hx index d296b0b0..6af40019 100644 --- a/source/funkin/play/components/ClearPercentCounter.hx +++ b/source/funkin/play/components/ClearPercentCounter.hx @@ -35,7 +35,7 @@ class ClearPercentCounter extends FlxTypedSpriteGroup super(x, y); flashShader = new PureColor(FlxColor.WHITE); - flashShader.colorSet = true; + flashShader.colorSet = false; curNumber = startingNumber; @@ -54,10 +54,7 @@ class ClearPercentCounter extends FlxTypedSpriteGroup */ public function flash(enabled:Bool):Void { - for (member in members) - { - member.shader = enabled ? flashShader : null; - } + flashShader.colorSet = enabled; } var tmr:Float = 0; @@ -98,6 +95,7 @@ class ClearPercentCounter extends FlxTypedSpriteGroup var yPos = (digitIndex - 1 + digitOffset) * (digitHeightOffset * this.scale.y); yPos += small ? 0 : 72; + trace('[COUNTER] Drawing digit ${num}'); if (digitIndex >= members.length) { // Three digits = LLR because the 1 and 0 won't be the same anyway. @@ -105,6 +103,8 @@ class ClearPercentCounter extends FlxTypedSpriteGroup // var variant:Bool = (seperatedScore.length % 2 != 0) ? (digitIndex % 2 == 0) : (digitIndex % 2 == 1); var numb:ClearPercentNumber = new ClearPercentNumber(xPos, yPos, num, variant, this.small); numb.scale.set(this.scale.x, this.scale.y); + numb.shader = flashShader; + numb.visible = true; add(numb); } else @@ -113,8 +113,15 @@ class ClearPercentCounter extends FlxTypedSpriteGroup // Reset the position of the number members[digitIndex].x = xPos + this.x; members[digitIndex].y = yPos + this.y; + members[digitIndex].visible = true; } } + trace('[COUNTER] Members: ${members.length}, expected members: ${seperatedScore.length + 1}'); + for (ind in (seperatedScore.length + 1)...(members.length)) + { + trace('Hiding digit ${ind}'); + members[ind].visible = false; + } } } From 640c1cf236f2578795c1385ac2ffad72a4095228 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 5 Jun 2024 00:49:59 -0400 Subject: [PATCH 101/131] Dave say 1 minute to make Dad sneak up and 2 minutes to play the cartoons --- source/funkin/ui/freeplay/DJBoyfriend.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/ui/freeplay/DJBoyfriend.hx b/source/funkin/ui/freeplay/DJBoyfriend.hx index 248526aa..bd2f73e4 100644 --- a/source/funkin/ui/freeplay/DJBoyfriend.hx +++ b/source/funkin/ui/freeplay/DJBoyfriend.hx @@ -27,8 +27,8 @@ class DJBoyfriend extends FlxAtlasSprite var gotSpooked:Bool = false; - static final SPOOK_PERIOD:Float = 120.0; - static final TV_PERIOD:Float = 180.0; + static final SPOOK_PERIOD:Float = 60.0; + static final TV_PERIOD:Float = 120.0; // Time since dad last SPOOKED you. var timeSinceSpook:Float = 0; From 9f3d80d1dbbefba5adc91aab84a0a25c91cb0394 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 5 Jun 2024 01:16:30 -0400 Subject: [PATCH 102/131] Cory made some chart tweaks. Plus some authorship changes. --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index efb7a833..6af09405 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit efb7a833a78ab9c3bd9fe36bb10a8adc6a87e30b +Subproject commit 6af0940504514701e3625b65d8332c27198e9198 From 3534ba6224d8dd950c9f599cedd15e597cc469ab Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 13:50:57 -0400 Subject: [PATCH 103/131] roses fix --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 6af09405..faef517a 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 6af0940504514701e3625b65d8332c27198e9198 +Subproject commit faef517a068bb6821d828462504d7baebc91306f From fa1fafba68be5b8abf0e7ad266b333a3d47c1875 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 14:13:06 -0400 Subject: [PATCH 104/131] less effin traces --- source/funkin/play/components/ClearPercentCounter.hx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/source/funkin/play/components/ClearPercentCounter.hx b/source/funkin/play/components/ClearPercentCounter.hx index 6af40019..e3d3795d 100644 --- a/source/funkin/play/components/ClearPercentCounter.hx +++ b/source/funkin/play/components/ClearPercentCounter.hx @@ -59,14 +59,14 @@ class ClearPercentCounter extends FlxTypedSpriteGroup var tmr:Float = 0; - override function update(elapsed:Float) + override function update(elapsed:Float):Void { super.update(elapsed); if (numberChanged) drawNumbers(); } - function drawNumbers() + function drawNumbers():Void { var seperatedScore:Array = []; var tempCombo:Int = Math.round(curNumber); @@ -83,7 +83,7 @@ class ClearPercentCounter extends FlxTypedSpriteGroup for (ind => num in seperatedScore) { - var digitIndex = ind + 1; + var digitIndex:Int = ind + 1; // If there's only one digit, move it to the right // If there's three digits, move them all to the left var digitOffset = (seperatedScore.length == 1) ? 1 : (seperatedScore.length == 3) ? -1 : 0; @@ -95,7 +95,6 @@ class ClearPercentCounter extends FlxTypedSpriteGroup var yPos = (digitIndex - 1 + digitOffset) * (digitHeightOffset * this.scale.y); yPos += small ? 0 : 72; - trace('[COUNTER] Drawing digit ${num}'); if (digitIndex >= members.length) { // Three digits = LLR because the 1 and 0 won't be the same anyway. @@ -116,10 +115,8 @@ class ClearPercentCounter extends FlxTypedSpriteGroup members[digitIndex].visible = true; } } - trace('[COUNTER] Members: ${members.length}, expected members: ${seperatedScore.length + 1}'); for (ind in (seperatedScore.length + 1)...(members.length)) { - trace('Hiding digit ${ind}'); members[ind].visible = false; } } From 6e761ba156de336af2b567e14dfbfdc36c796129 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 14:47:29 -0400 Subject: [PATCH 105/131] hardcode the songname position --- source/funkin/play/ResultState.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 6f540687..48fb3b04 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -691,13 +691,13 @@ class ResultState extends MusicBeatSubState { clearPercentSmall.x = (difficulty.x + difficulty.width) + 60; clearPercentSmall.y = -clearPercentSmall.height; - FlxTween.tween(clearPercentSmall, {y: 122 - 5}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.8}); + FlxTween.tween(clearPercentSmall, {y: 122 - 5}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.85}); } songName.y = -songName.height; var fuckedupnumber = (10) * (songName.text.length / 15); FlxTween.tween(songName, {y: diffYTween - 25 - fuckedupnumber}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9}); - songName.x = clearPercentSmall.x + clearPercentSmall.width - 30; + songName.x = clearPercentSmall.x + 94; new FlxTimer().start(timerLength, _ -> { var tempSpeed = FlxPoint.get(speedOfTween.x, speedOfTween.y); From 5bcc0f9b25c8dc4d8942fa87fb085430efc99575 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 15:02:29 -0400 Subject: [PATCH 106/131] partial sound loading should be more resiliant --- source/funkin/audio/FunkinSound.hx | 20 ++++++++++++++------ source/funkin/ui/freeplay/FreeplayState.hx | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx index 4cd0e755..4f61e70c 100644 --- a/source/funkin/audio/FunkinSound.hx +++ b/source/funkin/audio/FunkinSound.hx @@ -357,6 +357,11 @@ class FunkinSound extends FlxSound implements ICloneable var shouldLoadPartial = params.partialParams?.loadPartial ?? false; + // even if we arent' trying to partial load a song, we want to error out any songs in progress, + // so we don't get overlapping music if someone were to load a new song while a partial one is loading! + + emptyPartialQueue(); + if (shouldLoadPartial) { var music = FunkinSound.loadPartial(pathToUse, params.partialParams?.start ?? 0.0, params.partialParams?.end ?? 1.0, params?.startingVolume ?? 1.0, @@ -364,12 +369,6 @@ class FunkinSound extends FlxSound implements ICloneable if (music != null) { - while (partialQueue.length > 0) - { - @:nullSafety(Off) - partialQueue.pop().error("Cancel loading partial sound"); - } - partialQueue.push(music); @:nullSafety(Off) @@ -406,6 +405,15 @@ class FunkinSound extends FlxSound implements ICloneable } } + public static function emptyPartialQueue():Void + { + while (partialQueue.length > 0) + { + @:nullSafety(Off) + partialQueue.pop().error("Cancel loading partial sound"); + } + } + static var partialQueue:Array>> = []; /** diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 4fc94c2d..2ecbb573 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1769,6 +1769,8 @@ class FreeplayState extends MusicBeatSubState funnyScroll3.visible = false; new FlxTimer().start(1, function(tmr:FlxTimer) { + FunkinSound.emptyPartialQueue(); + Paths.setCurrentLevel(cap.songData.levelId); LoadingState.loadPlayState( { From c1bfc67f52d527bdeffa2a57c06a6dccbf105b0c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 15:43:25 -0400 Subject: [PATCH 107/131] remove effin trace --- source/funkin/ui/freeplay/SongMenuItem.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index fb91fbd1..a0fa0ae4 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -708,8 +708,6 @@ class FreeplayRank extends FlxSprite animation.play(val.getFreeplayRankIconAsset(), true, false); - trace(val.getFreeplayRankIconAsset()); - centerOffsets(false); switch (val) From eaa63196b3fda9243784c3706610361da861e45e Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 17:10:53 -0400 Subject: [PATCH 108/131] fix for dadbattle appearing on freeplay --- source/funkin/play/song/Song.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index fd006c0f..d8570372 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -378,7 +378,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry):Null { - if (diffId == null) diffId = listDifficulties(variation)[0]; + if (diffId == null) diffId = listDifficulties(variation, variations)[0]; if (variation == null) variation = Constants.DEFAULT_VARIATION; if (variations == null) variations = [variation]; From 8616722e6023729f354da0949d93a204ddd36dba Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 17:14:04 -0400 Subject: [PATCH 109/131] asset submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index faef517a..56fe3a36 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit faef517a068bb6821d828462504d7baebc91306f +Subproject commit 56fe3a3662bf5588b4f6cfec492efe5d4cfd600c From 4311dd20744fac60909f8ecf923ef3533654505b Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 17:58:22 -0400 Subject: [PATCH 110/131] hopefully dadbattle fix lol --- source/funkin/ui/freeplay/FreeplayState.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 2ecbb573..035ad261 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -2024,7 +2024,7 @@ class FreeplaySongData function set_currentDifficulty(value:String):String { - if (currentDifficulty == value) return value; + // if (currentDifficulty == value) return value; currentDifficulty = value; updateValues(displayedVariations); @@ -2064,7 +2064,7 @@ class FreeplaySongData function updateValues(variations:Array):Void { - this.songDifficulties = song.listDifficulties(variations, false, false); + this.songDifficulties = song.listDifficulties(null, variations, false, false); if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY; var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, variations); From bc783a278a0ebd7e69ba9f81698346198bfb98d8 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 5 Jun 2024 18:21:57 -0400 Subject: [PATCH 111/131] rank clipping fix --- source/funkin/ui/freeplay/FreeplayState.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 035ad261..a9721bd7 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1640,6 +1640,7 @@ class FreeplayState extends MusicBeatSubState { songCapsule.songData.currentDifficulty = currentDifficulty; songCapsule.init(null, null, songCapsule.songData); + songCapsule.checkClip(); } else { @@ -2024,8 +2025,6 @@ class FreeplaySongData function set_currentDifficulty(value:String):String { - // if (currentDifficulty == value) return value; - currentDifficulty = value; updateValues(displayedVariations); return value; From e27e96a1cb3ce63a3fc75054b67757e6ba6c20c1 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 5 Jun 2024 20:19:00 -0400 Subject: [PATCH 112/131] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 56fe3a36..68f223f9 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 56fe3a3662bf5588b4f6cfec492efe5d4cfd600c +Subproject commit 68f223f965c60a3874d7842ee2d448eee5afc87b From 642f272bce4a4399936fe1114e0db6795c0c19dd Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Thu, 6 Jun 2024 01:49:33 +0100 Subject: [PATCH 113/131] freeplay polish + new text --- source/funkin/play/song/Song.hx | 6 ++ source/funkin/ui/freeplay/FreeplayState.hx | 78 +++++++++++++--------- source/funkin/ui/freeplay/SongMenuItem.hx | 37 +++++++++- 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index d8570372..df3e343e 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -91,6 +91,12 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry):Void { busy = true; + grpCapsules.members[curSelected].sparkle.alpha = 0; // grpCapsules.members[curSelected].forcePosition(); if (fromResults != null) @@ -1088,6 +1089,8 @@ class FreeplayState extends MusicBeatSubState // NOW we can interact with the menu busy = false; + grpCapsules.members[curSelected].sparkle.alpha = 0.7; + playCurSongPreview(capsule); }, null); // FlxTween.tween(capsule, {"targetPos.x": capsule.targetPos.x - 50}, 0.6, @@ -1814,7 +1817,7 @@ class FreeplayState extends MusicBeatSubState function changeSelection(change:Int = 0):Void { - FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4); + if (!prepForNewRank) FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4); var prevSelected:Int = curSelected; @@ -1855,43 +1858,48 @@ class FreeplayState extends MusicBeatSubState if (index < curSelected) capsule.targetPos.y -= 100; // another 100 for good measure } - if (grpCapsules.countLiving() > 0) + if (grpCapsules.countLiving() > 0 && !prepForNewRank) { - if (curSelected == 0) - { - FunkinSound.playMusic('freeplayRandom', - { - startingVolume: 0.0, - overrideExisting: true, - restartTrack: false - }); - FlxG.sound.music.fadeIn(2, 0, 0.8); - } - else - { - var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; - FunkinSound.playMusic(daSongCapsule.songData.songId, - { - startingVolume: 0.0, - overrideExisting: true, - restartTrack: false, - pathsFunction: INST, - suffix: potentiallyErect, - partialParams: - { - loadPartial: true, - start: 0.05, - end: 0.25 - }, - onLoad: function() { - FlxG.sound.music.fadeIn(2, 0, 0.4); - } - }); - } + playCurSongPreview(daSongCapsule); grpCapsules.members[curSelected].selected = true; } } + public function playCurSongPreview(daSongCapsule:SongMenuItem):Void + { + if (curSelected == 0) + { + FunkinSound.playMusic('freeplayRandom', + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false + }); + FlxG.sound.music.fadeIn(2, 0, 0.8); + } + else + { + var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : ""; + FunkinSound.playMusic(daSongCapsule.songData.songId, + { + startingVolume: 0.0, + overrideExisting: true, + restartTrack: false, + pathsFunction: INST, + suffix: potentiallyErect, + partialParams: + { + loadPartial: true, + start: 0.05, + end: 0.25 + }, + onLoad: function() { + FlxG.sound.music.fadeIn(2, 0, 0.4); + } + }); + } + } + /** * Build an instance of `FreeplayState` that is above the `MainMenuState`. * @return The MainMenuState with the FreeplayState as a substate. @@ -2004,6 +2012,8 @@ class FreeplaySongData */ public var isFav:Bool = false; + public var isNew:Bool = false; + var song:Song; public var levelId(default, null):String = ''; @@ -2083,6 +2093,8 @@ class FreeplaySongData } this.scoringRank = Save.instance.getSongRank(songId, currentDifficulty); + + this.isNew = song.isSongNew(currentDifficulty); } } diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index a0fa0ae4..dc30b434 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -21,6 +21,8 @@ import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.addons.effects.FlxTrail; import funkin.play.scoring.Scoring.ScoringRank; +import funkin.save.Save; +import funkin.save.Save.SaveScoreData; import flixel.util.FlxColor; class SongMenuItem extends FlxSpriteGroup @@ -76,6 +78,10 @@ class SongMenuItem extends FlxSpriteGroup var impactThing:FunkinSprite; + public var sparkle:FlxSprite; + + var sparkleTimer:FlxTimer; + public function new(x:Float, y:Float) { super(x, y); @@ -110,7 +116,7 @@ class SongMenuItem extends FlxSpriteGroup newText.animation.play('newAnim', true); newText.setGraphicSize(Std.int(newText.width * 0.9)); - newText.visible = false; + // newText.visible = false; add(newText); @@ -153,6 +159,18 @@ class SongMenuItem extends FlxSpriteGroup blurredRanking.shader = new GaussianBlurShader(1); add(blurredRanking); + sparkle = new FlxSprite(ranking.x, ranking.y); + sparkle.frames = Paths.getSparrowAtlas('freeplay/sparkle'); + sparkle.animation.addByPrefix('sparkle', 'sparkle', 24, false); + sparkle.animation.play('sparkle', true); + sparkle.scale.set(0.8, 0.8); + sparkle.blend = BlendMode.ADD; + + sparkle.visible = false; + sparkle.alpha = 0.7; + + add(sparkle); + // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); // ranking.scale.x = ranking.scale.y = realScaled; // ranking.alpha = 0.75; @@ -218,6 +236,13 @@ class SongMenuItem extends FlxSpriteGroup setVisibleGrp(false); } + function sparkleEffect(timer:FlxTimer):Void + { + sparkle.setPosition(FlxG.random.float(ranking.x - 20, ranking.x + 3), FlxG.random.float(ranking.y - 29, ranking.y + 4)); + sparkle.animation.play('sparkle', true); + sparkleTimer = new FlxTimer().start(FlxG.random.float(1.2, 4.5), sparkleEffect); + } + // no way to grab weeks rn, so this needs to be done :/ // negative values mean weekends function checkWeek(name:String):Void @@ -415,8 +440,17 @@ class SongMenuItem extends FlxSpriteGroup function updateScoringRank(newRank:Null):Void { + if (sparkleTimer != null) sparkleTimer.cancel(); + sparkle.visible = false; + this.ranking.rank = newRank; this.blurredRanking.rank = newRank; + + if (newRank == PERFECT_GOLD) + { + sparkleTimer = new FlxTimer().start(1, sparkleEffect); + sparkle.visible = true; + } } function set_hsvShader(value:HSVShader):HSVShader @@ -468,6 +502,7 @@ class SongMenuItem extends FlxSpriteGroup updateBPM(Std.int(songData?.songStartingBpm) ?? 0); updateDifficultyRating(songData?.difficultyRating ?? 0); updateScoringRank(songData?.scoringRank); + newText.visible = songData?.isNew; // Update opacity, offsets, etc. updateSelected(); From b7eed4c4d3a1c1b4331e254f7eea75ff334fc3f4 Mon Sep 17 00:00:00 2001 From: FabsTheFabs Date: Thu, 6 Jun 2024 01:50:19 +0100 Subject: [PATCH 114/131] assets submoddd!!!!! --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 56fe3a36..36e39546 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 56fe3a3662bf5588b4f6cfec492efe5d4cfd600c +Subproject commit 36e3954675428214ae6d3ce5123ad3bc9882ea8b From 2596e6369ecbe27de8db7b86f6b3dbd05319e5fc Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 6 Jun 2024 14:00:22 -0400 Subject: [PATCH 115/131] More chart changes by SpazKid + changelog update --- CHANGELOG.md | 10 +++++++--- assets | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 898978ca..42f1fee0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,13 +15,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a new Scroll Speed chart event to change the note speed mid-song (thanks ) ### Changed - Tweaked the charts for several songs: + - Tutorial (increased the note speed slightly) + - Spookeez - Monster - Winter Horrorland + - M.I.L.F. + - Senpai (increased the note speed) + - Roses + - Thorns (increased the note speed slightly) + - Ugh - Stress - Lit Up - - Tutorial (increased the note speed slightly) - - Senpai (increased the note speed) - - Thorns (increased the note speed slightly) - Favorite songs marked in Freeplay are now stored between sessions. - In the event that the game cannot load your save data, it will now perform a backup before clearing it, so that we can try to repair it in the future. - Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!) diff --git a/assets b/assets index 56fe3a36..6e124504 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 56fe3a3662bf5588b4f6cfec492efe5d4cfd600c +Subproject commit 6e124504f777048d357c4b94737dda1b569b4d03 From 700b6e11b8f06a9ad12c152e5974d5b4f016730c Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 6 Jun 2024 19:05:05 -0400 Subject: [PATCH 116/131] Update assets submodule --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 6e124504..862b5135 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 6e124504f777048d357c4b94737dda1b569b4d03 +Subproject commit 862b51355622c29b5b11ff8ce979afeb53df4636 From e4647e9e2d754a8128a25dcc3d75e463fa8aed4c Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 6 Jun 2024 19:46:44 -0400 Subject: [PATCH 117/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 36e39546..0062c05d 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 36e3954675428214ae6d3ce5123ad3bc9882ea8b +Subproject commit 0062c05d559ae281ce39f8df3da6efb1f92ca808 From 0bb22b60d9b4703ddcfc2def84bf1a574f2631a4 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 6 Jun 2024 19:55:50 -0400 Subject: [PATCH 118/131] update game version --- Project.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.xml b/Project.xml index fcd29a25..d93cf3e4 100644 --- a/Project.xml +++ b/Project.xml @@ -2,7 +2,7 @@ - + From 4f0e77c974c7a62fb1deb6cc351668a4b01a4f92 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 6 Jun 2024 20:20:54 -0400 Subject: [PATCH 119/131] update hmm --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index ab55e30b..4f3d9ac4 100644 --- a/hmm.json +++ b/hmm.json @@ -56,7 +56,7 @@ "name": "funkin.vis", "type": "git", "dir": null, - "ref": "c6a1e24d48646849ea63563ca45561512c953779", + "ref": "38261833590773cb1de34ac5d11e0825696fc340", "url": "https://github.com/FunkinCrew/funkVis" }, { From e01e4d1e769ac111352ff3ecdbe620e7a2908363 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 6 Jun 2024 20:21:37 -0400 Subject: [PATCH 120/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 862b5135..e8fc4616 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 862b51355622c29b5b11ff8ce979afeb53df4636 +Subproject commit e8fc4616c167de66c4eddcfe1cbe51bae83536da From 7c638e02740a4937f2fb54b282f79ef25e2634e8 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 6 Jun 2024 20:26:25 -0400 Subject: [PATCH 121/131] Add satin panties erect difficulty chart --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 0062c05d..e8bfc746 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0062c05d559ae281ce39f8df3da6efb1f92ca808 +Subproject commit e8bfc7461a403e108a7f7b5fa4eebba38bb6a5fe From 715e834753fe18c4fa62e0aca627f80559ef8f82 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 6 Jun 2024 20:30:15 -0400 Subject: [PATCH 122/131] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 898978ca..acb85df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,12 +25,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Favorite songs marked in Freeplay are now stored between sessions. - In the event that the game cannot load your save data, it will now perform a backup before clearing it, so that we can try to repair it in the future. - Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!) -- Improved logic for NoteHitScriptEvents, allowing you to view the hit diff and modify whether a note hit is a combo break (thanks nebulazorua!) - Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!) - Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame. ### Fixed - Fixed a bug where the game would silently fail to load saves on HTML5 - Fixed some bugs with the props on the Story Menu not bopping properly +- Improved offsets for Pico and Tankman opponents so they don't slide around as much. - Additional fixes to the Loading bar on HTML5 (thanks lemz1!) - Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!) - Fixed a camera bug in the Main Menu (thanks richTrash21!) From c54c10f562e1931f39f0eb41d1f41c16c8505447 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 6 Jun 2024 20:46:12 -0400 Subject: [PATCH 123/131] lower fft res on desktop --- source/funkin/audio/visualize/ABotVis.hx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index ed22092b..1b046314 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -55,6 +55,13 @@ class ABotVis extends FlxTypedSpriteGroup { @:privateAccess analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.1, 30); + + #if desktop + // On desktop it uses FFT stuff that isn't as optimized as the direct browser stuff we use on HTML5 + // So we want to manually change it! + analyzer.fftN = 512; + #end + // analyzer.maxDb = -35; // analyzer.fftN = 2048; } From 7214e159e0174a04b21fd4f01bceaa405e062e4f Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 6 Jun 2024 20:50:53 -0400 Subject: [PATCH 124/131] update grig --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 4f3d9ac4..68e0c5cb 100644 --- a/hmm.json +++ b/hmm.json @@ -63,7 +63,7 @@ "name": "grig.audio", "type": "git", "dir": "src", - "ref": "cbf91e2180fd2e374924fe74844086aab7891666", + "ref": "57f5d47f2533fd0c3dcd025a86cb86c0dfa0b6d2", "url": "https://gitlab.com/haxe-grig/grig.audio.git" }, { From e2fbeeb13e37070f59627751216218f943f84a3d Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Thu, 6 Jun 2024 21:18:53 -0400 Subject: [PATCH 125/131] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index e8bfc746..4427687c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e8bfc7461a403e108a7f7b5fa4eebba38bb6a5fe +Subproject commit 4427687c487d643c6051f8c4610470326c87ea4d From 6665924dd968ff96d074843988d34c64035aa479 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 6 Jun 2024 23:28:41 -0400 Subject: [PATCH 126/131] We forgot to credit burgerballs! --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e44005ff..1c4969cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.4.0] - 2024-05-?? +## [0.4.0] - 2024-06-06 ### Added - 2 new Erect remixes, Eggnog and Satin Panties. Check them out from the Freeplay menu! - Major visual improvements to the Results screen, with additional animations and audio based on your performance. @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Freeplay now plays a preview of songs when you hover over them. - Added a Charter field to the chart format, to allow for crediting the creator of a level's chart. - You can see who charted a song from the Pause menu. -- Added a new Scroll Speed chart event to change the note speed mid-song (thanks ) +- Added a new Scroll Speed chart event to change the note speed mid-song (thanks burgerballs!) ### Changed - Tweaked the charts for several songs: - Tutorial (increased the note speed slightly) From 8700db198890ba5e83b0b0df22dc4b878a97dce0 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 6 Jun 2024 23:51:22 -0400 Subject: [PATCH 127/131] Make sure to credit all the community contributions properly. --- CHANGELOG.md | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c4969cd..90d2a500 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,23 +32,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!) - Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame. ### Fixed +- Fixed an issue where Nene's visualizer would not play on Desktop builds - Fixed a bug where the game would silently fail to load saves on HTML5 - Fixed some bugs with the props on the Story Menu not bopping properly - Improved offsets for Pico and Tankman opponents so they don't slide around as much. -- Additional fixes to the Loading bar on HTML5 (thanks lemz1!) -- Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!) -- Fixed a camera bug in the Main Menu (thanks richTrash21!) -- Fixed a bug where changing difficulties in Story mode wouldn't update the score (thanks sectorA!) -- Fixed a crash in Freeplay caused by a level referencing an invalid song (thanks gamerbross!) -- Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!) -- Fixed a bug where the Chart Editor Playtest would crash when losing (thanks gamerbross!) -- Fixed a bug where hold notes would display improperly in the Chart Editor when downscroll was enabled for gameplay (thanks gamerbross!) -- Fixed a bug where hold notes would be positioned wrong on downscroll (thanks MaybeMaru!) -- Removed a large number of unused imports to optimize builds (thanks Ethan-makes-music!) -- Improved debug logging for unscripted stages (thanks gamerbross!) -- Made improvements to compiling documentation (thanks gedehari!) - Fixed a crash on Linux caused by an old version of hxCodec (thanks Noobz4Life!) - Optimized animation handling for characters (thanks richTrash21!) +- Made improvements to compiling documentation (thanks gedehari!) +- Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!) +- Fixed a bug where the Chart Editor Playtest would crash when losing (thanks gamerbross!) +- Removed a large number of unused imports to optimize builds (thanks Ethan-makes-music!) +- Fixed a bug where hold notes would be positioned wrong on downscroll (thanks MaybeMaru!) +- Additional fixes to the Loading bar on HTML5 (thanks lemz1!) +- Fixed a crash in Freeplay caused by a level referencing an invalid song (thanks gamerbross!) +- Improved debug logging for unscripted stages (thanks gamerbross!) +- Fixed a bug where changing difficulties in Story mode wouldn't update the score (thanks sectorA!) +- Fixed an issue where the Chart Editor would use an incorrect instrumental on imported Legacy songs (thanks gamerbross!) +- Fixed a camera bug in the Main Menu (thanks richTrash21!) +- Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!) +- Fixed a bug where opening the game from the command line would crash the preloader (thanks NotHyper474!) +- Fixed a bug where hold notes would display improperly in the Chart Editor when downscroll was enabled for gameplay (thanks gamerbross!) +- Fixed a bug where characters would sometimes use the wrong scale value (thanks PurSnake!) - Additional bug fixes and optimizations. ## [0.3.3] - 2024-05-14 From 3567e4e8e441613c0ed72d2cf13567568964cb7e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 7 Jun 2024 00:43:31 -0400 Subject: [PATCH 128/131] Writing down more changes as I remember them --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90d2a500..35618dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Stress - Lit Up - Favorite songs marked in Freeplay are now stored between sessions. +- The Freeplay easter eggs are now easier to see. - In the event that the game cannot load your save data, it will now perform a backup before clearing it, so that we can try to repair it in the future. - Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!) - Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!) From d4a524bbcbee7e4ba10da77fbfb4a9d6964a9bbe Mon Sep 17 00:00:00 2001 From: An-enderman <126195358+An-enderman@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:40:37 +0200 Subject: [PATCH 129/131] Update COMPILING, adding one step I added the step that says to download Git, because the command "hmm install" requires Git to work. --- docs/COMPILING.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index 7278e027..6fbcfe62 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -6,9 +6,10 @@ - `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` - If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way. 2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`) -3. Install all haxelibs of the current branch by running `hmm install` -4. Setup lime: `haxelib run lime setup` -5. Platform setup +3. Download Git from [git-scm.com](https://www.git-scm.com) +4. Install all haxelibs of the current branch by running `hmm install` +5. Setup lime: `haxelib run lime setup` +6. Platform setup - For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) - When prompted, select "Individual Components" and make sure to download the following: - MSVC v143 VS 2022 C++ x64/x86 build tools @@ -16,5 +17,5 @@ - Mac: [`lime setup mac` Documentation](https://lime.openfl.org/docs/advanced-setup/macos/) - Linux: [`lime setup linux` Documentation](https://lime.openfl.org/docs/advanced-setup/linux/) - HTML5: Compiles without any extra setup -6. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` -7. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). +7. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` +8. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). From a7e33e73ab13ad26db6feede8d6eb775edb9aa0a Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 7 Jun 2024 11:24:31 -0400 Subject: [PATCH 130/131] assets submod updated and gitmodules fix for public --- .gitmodules | 4 ++-- assets | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 452c0089..be5e0aaa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "assets"] path = assets - url = https://github.com/FunkinCrew/Funkin-Assets-secret + url = https://github.com/FunkinCrew/funkin.assets [submodule "art"] path = art - url = https://github.com/FunkinCrew/Funkin-Art-secret + url = https://github.com/FunkinCrew/funkin.art diff --git a/assets b/assets index 4427687c..3b8235e9 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4427687c487d643c6051f8c4610470326c87ea4d +Subproject commit 3b8235e953505a6fe7f4ff253f5a99b9a7b9857a From 73984ea9d6830493b004800d85960b6ca69a85f8 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Fri, 7 Jun 2024 11:28:35 -0400 Subject: [PATCH 131/131] fix art submod --- art | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/art b/art index faeba700..66572f85 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit faeba700c5526bd4fd57ccc927d875c82b9d3553 +Subproject commit 66572f85d826ce2ec1d45468c12733b161237ffa