2023-11-07 04:04:22 -05:00
package funkin . ui . freeplay ;
2021-04-07 20:19:49 -04:00
2023-10-10 23:32:01 -04:00
import flixel . addons . transition . FlxTransitionableState ;
import flixel . addons . ui . FlxInputText ;
2021-08-21 20:45:03 -04:00
import flixel . FlxCamera ;
2020-10-21 14:05:27 -04:00
import flixel . FlxSprite ;
2021-10-21 23:08:48 -04:00
import flixel . group . FlxGroup ;
2023-10-10 23:32:01 -04:00
import flixel . group . FlxGroup . FlxTypedGroup ;
2024-03-11 23:42:32 -04:00
import flixel . group . FlxSpriteGroup . FlxTypedSpriteGroup ;
2021-08-21 19:53:08 -04:00
import flixel . input . touch . FlxTouch ;
2021-08-24 15:28:04 -04:00
import flixel . math . FlxAngle ;
import flixel . math . FlxPoint ;
2023-10-10 23:32:01 -04:00
import flixel . system . debug . watch . Tracker . TrackerProfile ;
2020-10-21 14:05:27 -04:00
import flixel . text . FlxText ;
2021-10-21 23:08:48 -04:00
import flixel . tweens . FlxEase ;
2021-03-02 00:46:28 -05:00
import flixel . tweens . FlxTween ;
2024-06-20 16:17:53 -04:00
import flixel . tweens . misc . ShakeTween ;
2020-11-06 21:17:27 -05:00
import flixel . util . FlxColor ;
2021-10-21 23:08:48 -04:00
import flixel . util . FlxSpriteUtil ;
2021-10-21 17:40:53 -04:00
import flixel . util . FlxTimer ;
2024-03-11 23:42:32 -04:00
import funkin . audio . FunkinSound ;
2024-06-18 17:56:24 -04:00
import funkin . data . freeplay . player . PlayerRegistry ;
2023-10-10 23:32:01 -04:00
import funkin . data . song . SongRegistry ;
2024-06-20 16:17:53 -04:00
import funkin . data . story . level . LevelRegistry ;
import funkin . effects . IntervalShake ;
import funkin . graphics . adobeanimate . FlxAtlasSprite ;
2024-03-11 23:42:32 -04:00
import funkin . graphics . FunkinCamera ;
import funkin . graphics . FunkinSprite ;
2023-11-07 04:04:22 -05:00
import funkin . graphics . shaders . AngleMask ;
2024-06-20 16:17:53 -04:00
import funkin . graphics . shaders . GaussianBlurShader ;
2023-11-07 04:04:22 -05:00
import funkin . graphics . shaders . HSVShader ;
import funkin . graphics . shaders . PureColor ;
import funkin . graphics . shaders . StrokeShader ;
2024-01-11 00:30:00 -05:00
import funkin . input . Controls ;
2023-10-10 23:32:01 -04:00
import funkin . play . PlayStatePlaylist ;
2024-06-20 16:17:53 -04:00
import funkin . play . scoring . Scoring ;
import funkin . play . scoring . Scoring . ScoringRank ;
2023-10-10 23:32:01 -04:00
import funkin . play . song . Song ;
import funkin . save . Save ;
import funkin . save . Save . SaveScoreData ;
2024-01-11 00:30:00 -05:00
import funkin . ui . AtlasText ;
2024-06-20 16:17:53 -04:00
import funkin . ui . freeplay . charselect . PlayableCharacter ;
import funkin . ui . freeplay . SongMenuItem . FreeplayRank ;
2024-01-11 00:30:00 -05:00
import funkin . ui . mainmenu . MainMenuState ;
2023-11-07 04:04:22 -05:00
import funkin . ui . MusicBeatSubState ;
2024-06-20 16:17:53 -04:00
import funkin . ui . story . Level ;
2023-11-07 04:04:22 -05:00
import funkin . ui . transition . LoadingState ;
import funkin . ui . transition . StickerSubState ;
import funkin . util . MathUtil ;
2024-06-20 16:17:53 -04:00
import funkin . util . SortUtil ;
2022-03-23 23:27:48 -04:00
import lime . utils . Assets ;
2024-06-20 16:17:53 -04:00
import openfl . display . BlendMode ;
2020-10-21 14:05:27 -04:00
2024-02-05 13:35:30 -05:00
/ * *
* Parameters used to initialize the FreeplayState .
* /
typedef FreeplayStateParams =
{
2024-02-05 21:35:58 -05:00
? character : String ,
2024-05-30 05:25:51 -04:00
? fromResults : FromResultsParams ,
} ;
/ * *
* A set of parameters for t r a n s i t i o n i n g t o t h e F r e e p l a y S t a t e f r o m t h e R e s u l t s S t a t e .
* /
typedef FromResultsParams =
{
/ * *
* The previous rank the song hand , if a n y . N u l l i f i t h a d n o s c o r e b e f o r e .
* /
var ? oldRank: ScoringRank ;
2024-06-01 19:25:52 -04:00
/ * *
* Whether or not to play the rank animation on returning to freeplay .
* /
var playRankAnim: Bool ;
2024-05-30 05:25:51 -04:00
/ * *
* The new rank t h e s o n g h a s .
* /
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 ;
2024-02-05 13:35:30 -05:00
} ;
2024-03-20 14:37:24 -04:00
/ * *
* The state for t h e f r e e p l a y m e n u , a l l o w i n g t h e p l a y e r t o s e l e c t a n y s o n g t o p l a y .
* /
2024-06-20 16:17:53 -04:00
@ : nullSafety
2023-06-01 18:52:58 -04:00
class FreeplayState extends MusicBeatSubState
2020-10-21 14:05:27 -04:00
{
2024-02-09 23:13:40 -05:00
//
// Params
//
/ * *
* The current character for t h i s F r e e p l a y S t a t e .
* You can ' t c h a n g e t h i s w i t h o u t t r a n s i t i o n i n g t o a n e w F r e e p l a y S t a t e .
* /
2024-06-18 17:56:24 -04:00
final currentCharacterId : String ;
final currentCharacter : PlayableCharacter ;
2024-02-05 21:35:58 -05:00
2024-02-09 14:58:57 -05:00
/ * *
* For the audio preview , the duration of the fade - i n effect .
* /
public static final FADE_IN_DURATION : Float = 0.5 ;
/ * *
* For the audio preview , the duration of the fade - out effect .
2024-05-31 17:16:26 -04:00
*
2024-02-09 14:58:57 -05:00
* /
public static final FADE_OUT_DURATION : Float = 0.25 ;
/ * *
* For the audio preview , the volume at which the fade - i n starts .
* /
public static final FADE_IN_START_VOLUME : Float = 0.25 ;
/ * *
* For the audio preview , the volume at which the fade - i n ends .
* /
public static final FADE_IN_END_VOLUME : Float = 1.0 ;
/ * *
* For the audio preview , the volume at which the fade - out starts .
* /
public static final FADE_OUT_END_VOLUME : Float = 0.0 ;
2023-10-12 03:20:21 -04:00
var songs: Array < Null < FreeplaySongData > > = [ ] ;
var diffIdsCurrent: Array < String > = [ ] ;
var diffIdsTotal: Array < String > = [ ] ;
2020-10-21 14:05:27 -04:00
2023-01-22 19:55:30 -05:00
var curSelected: Int = 0 ;
2023-10-12 03:20:21 -04:00
var currentDifficulty: String = Constants . DEFAULT_DIFFICULTY ;
2020-11-06 21:17:27 -05:00
2023-01-22 19:55:30 -05:00
var fp: FreeplayScore ;
2024-01-11 00:30:00 -05:00
var txtCompletion: AtlasText ;
2023-01-22 19:55:30 -05:00
var lerpCompletion: Float = 0 ;
var intendedCompletion: Float = 0 ;
var lerpScore: Float = 0 ;
var intendedScore: Int = 0 ;
2020-10-21 14:05:27 -04:00
2023-10-12 03:20:21 -04:00
var grpDifficulties: FlxTypedSpriteGroup < DifficultySprite > ;
2021-12-07 17:41:18 -05:00
2023-01-22 19:55:30 -05:00
var coolColors: Array < Int > = [
2024-03-20 14:37:24 -04:00
0xFF9271FD ,
0xFF9271FD ,
0xFF223344 ,
2023-01-22 19:55:30 -05:00
0xFF941653 ,
2024-03-20 14:37:24 -04:00
0xFFFC96D7 ,
0xFFA0D1FF ,
0xFFFF78BF ,
0xFFF6B604
2023-01-22 19:55:30 -05:00
] ;
2021-03-02 00:46:28 -05:00
2023-01-22 22:25:45 -05:00
var grpSongs: FlxTypedGroup < Alphabet > ;
var grpCapsules: FlxTypedGroup < SongMenuItem > ;
var curPlaying: Bool = false ;
2020-11-01 14:16:22 -05:00
2024-06-20 16:17:53 -04:00
var dj: Null < FreeplayDJ > = null ;
2022-11-15 02:23:44 -05:00
2024-03-20 14:37:24 -04:00
var ostName: FlxText ;
var albumRoll: AlbumRoll ;
2023-11-07 18:53:50 -05:00
var letterSort: LetterSort ;
2024-03-20 14:37:24 -04:00
var exitMovers: ExitMoverData = new Map ( ) ;
2022-09-26 18:22:45 -04:00
2024-06-20 16:17:53 -04:00
var stickerSubState: Null < StickerSubState > = null ;
2023-04-06 01:39:27 -04:00
2024-04-01 21:59:53 -04:00
public static var rememberedDifficulty: Null < String > = Constants . DEFAULT_DIFFICULTY ;
2024-04-03 01:40:08 -04:00
public static var rememberedSongId: Null < String > = ' t u t o r i a l ' ;
2023-10-12 03:20:21 -04:00
2024-05-29 23:34:00 -04:00
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 ;
2024-05-30 05:25:51 -04:00
var fromResultsParams: Null < FromResultsParams > = null ;
2024-05-31 05:39:53 -04:00
var prepForNewRank: Bool = false ;
2024-02-05 21:35:58 -05:00
public function n e w ( ? params : FreeplayStateParams , ? stickers : StickerSubState )
2023-04-06 01:39:27 -04:00
{
2024-06-18 17:56:24 -04:00
currentCharacterId = params ? . character ? ? Constants . DEFAULT_CHARACTER ;
2024-06-20 16:17:53 -04:00
var fetchPlayableCharacter = function ( ) : PlayableCharacter {
var result = PlayerRegistry . instance . fetchEntry ( params ? . character ? ? Constants . DEFAULT_CHARACTER ) ;
if ( result == null ) throw ' N o v a l i d p l a y a b l e c h a r a c t e r w i t h i d ${ params ? . character } ' ;
return result ;
} ;
currentCharacter = fetchPlayableCharacter ( ) ;
2024-02-05 13:35:30 -05:00
2024-05-30 05:25:51 -04:00
fromResultsParams = params ? . fromResults ;
2024-06-01 19:25:52 -04:00
if ( fromResultsParams ? . playRankAnim == true )
{
2024-05-31 05:39:53 -04:00
prepForNewRank = true ;
}
2024-06-20 16:17:53 -04:00
super ( FlxColor . TRANSPARENT ) ;
2024-06-20 01:24:36 -04:00
if ( stickers ? . members != null )
2023-04-06 01:39:27 -04:00
{
stickerSubState = stickers ;
}
2024-06-20 16:17:53 -04:00
// We build a bunch of sprites BEFORE create() so we can guarantee they aren't null later on.
albumRoll = new AlbumRoll ( ) ;
fp = new FreeplayScore ( 460 , 60 , 7 , 100 ) ;
cardGlow = new FlxSprite ( - 30 , - 30 ) . loadGraphic ( Paths . image ( ' f r e e p l a y / c a r d G l o w ' ) ) ;
confirmGlow = new FlxSprite ( - 30 , 240 ) . loadGraphic ( Paths . image ( ' f r e e p l a y / c o n f i r m G l o w ' ) ) ;
confirmTextGlow = new FlxSprite ( - 8 , 115 ) . loadGraphic ( Paths . image ( ' f r e e p l a y / g l o w i n g T e x t ' ) ) ;
rankCamera = new FunkinCamera ( ' r a n k C a m e r a ' , 0 , 0 , FlxG . width , FlxG . height ) ;
funnyCam = new FunkinCamera ( ' f r e e p l a y F u n n y ' , 0 , 0 , FlxG . width , FlxG . height ) ;
funnyScroll = new BGScrollingText ( 0 , 220 , currentCharacter . getFreeplayDJText ( 1 ) , FlxG . width / 2 , false , 60 ) ;
funnyScroll2 = new BGScrollingText ( 0 , 335 , currentCharacter . getFreeplayDJText ( 1 ) , FlxG . width / 2 , false , 60 ) ;
grpCapsules = new FlxTypedGroup < SongMenuItem > ( ) ;
grpDifficulties = new FlxTypedSpriteGroup < DifficultySprite > ( - 300 , 80 ) ;
letterSort = new LetterSort ( 400 , 75 ) ;
grpSongs = new FlxTypedGroup < Alphabet > ( ) ;
moreWays = new BGScrollingText ( 0 , 160 , currentCharacter . getFreeplayDJText ( 2 ) , FlxG . width , true , 43 ) ;
moreWays2 = new BGScrollingText ( 0 , 397 , currentCharacter . getFreeplayDJText ( 2 ) , FlxG . width , true , 43 ) ;
pinkBack = FunkinSprite . create ( ' f r e e p l a y / p i n k B a c k ' ) ;
rankBg = new FunkinSprite ( 0 , 0 ) ;
rankVignette = new FlxSprite ( 0 , 0 ) . loadGraphic ( Paths . image ( ' f r e e p l a y / r a n k V i g n e t t e ' ) ) ;
sparks = new FlxSprite ( 0 , 0 ) ;
sparksADD = new FlxSprite ( 0 , 0 ) ;
txtCompletion = new AtlasText ( 1185 , 87 , ' 6 9 ' , AtlasFont . FREEPLAY_CLEAR ) ;
txtNuts = new BGScrollingText ( 0 , 285 , currentCharacter . getFreeplayDJText ( 3 ) , FlxG . width / 2 , true , 43 ) ;
ostName = new FlxText ( 8 , 8 , FlxG . width - 8 - 8 , ' O F F I C I A L O S T ' , 48 ) ;
orangeBackShit = new FunkinSprite ( 84 , 440 ) . makeSolidColor ( Std . int ( pinkBack . width ) , 75 , 0xFFFEDA00 ) ;
bgDad = new FlxSprite ( pinkBack . width * 0.74 , 0 ) . loadGraphic ( Paths . image ( ' f r e e p l a y / f r e e p l a y B G d a d ' ) ) ;
alsoOrangeLOL = new FunkinSprite ( 0 , orangeBackShit . y ) . makeSolidColor ( 100 , Std . int ( orangeBackShit . height ) , 0xFFFFD400 ) ;
confirmGlow2 = new FlxSprite ( confirmGlow . x , confirmGlow . y ) . loadGraphic ( Paths . image ( ' f r e e p l a y / c o n f i r m G l o w 2 ' ) ) ;
funnyScroll3 = new BGScrollingText ( 0 , orangeBackShit . y + 10 , currentCharacter . getFreeplayDJText ( 1 ) , FlxG . width / 2 , 60 ) ;
backingTextYeah = new FlxAtlasSprite ( 640 , 370 , Paths . animateAtlas ( " f r e e p l a y / b a c k i n g - t e x t - y e a h " ) ,
{
FrameRate : 24.0 ,
Reversed : false ,
// ?OnComplete:Void -> Void,
ShowPivot : false ,
Antialiasing : true ,
ScrollFactor : new FlxPoint ( 1 , 1 ) ,
} ) ;
2023-04-06 01:39:27 -04:00
}
override function create ( ) : Void
2023-01-22 19:55:30 -05:00
{
2023-04-06 01:39:27 -04:00
super . create ( ) ;
2024-05-02 23:02:47 -04:00
FlxG . state . persistentUpdate = false ;
2023-01-22 19:55:30 -05:00
FlxTransitionableState . skipNextTransIn = true ;
2021-10-21 23:08:48 -04:00
2023-04-06 01:39:27 -04:00
if ( stickerSubState != null )
{
this . persistentUpdate = true ;
this . persistentDraw = true ;
openSubState ( stickerSubState ) ;
stickerSubState . degenStickers ( ) ;
}
2023-01-22 19:55:30 -05:00
#if discord_rpc
// Updating Discord Rich Presence
2024-03-16 00:55:57 -04:00
DiscordClient . changePresence ( ' I n t h e M e n u s ' , null ) ;
2023-01-22 19:55:30 -05:00
#end
2021-05-06 06:54:57 -04:00
2023-01-22 19:55:30 -05:00
var isDebug: Bool = false ;
2021-05-06 06:54:57 -04:00
2023-01-22 19:55:30 -05:00
#if debug
isDebug = true ;
#end
2021-05-06 06:54:57 -04:00
2024-05-31 05:39:53 -04:00
if ( prepForNewRank == false )
{
FunkinSound . playMusic ( ' f r e a k y M e n u ' ,
2024-06-01 19:25:52 -04:00
{
overrideExisting : true ,
restartTrack : false
} ) ;
2024-05-31 05:39:53 -04:00
}
2020-11-01 14:16:22 -05:00
2023-10-10 23:32:01 -04:00
// Add a null entry that represents the RANDOM option
songs . push ( null ) ;
2021-03-01 18:59:51 -05:00
2023-09-28 20:29:19 -04:00
// programmatically adds the songs via LevelRegistry and SongRegistry
2024-05-01 21:51:33 -04:00
for ( levelId in LevelRegistry . instance . listSortedLevelIds ( ) )
2023-09-28 20:29:19 -04:00
{
2024-06-20 16:17:53 -04:00
var level: Null < Level > = LevelRegistry . instance . fetchEntry ( levelId ) ;
2024-05-11 14:11:51 -04:00
if ( level == null )
{
trace ( ' [ W A R N ] C o u l d n o t f i n d l e v e l w i t h i d ( ${ levelId } ) ' ) ;
continue ;
}
for ( songId in level . getSongs ( ) )
2023-09-28 20:29:19 -04:00
{
2024-06-20 16:17:53 -04:00
var song: Null < Song > = SongRegistry . instance . fetchEntry ( songId ) ;
2023-10-12 03:20:21 -04:00
2024-05-11 14:11:51 -04:00
if ( song == null )
{
trace ( ' [ W A R N ] C o u l d n o t f i n d s o n g w i t h i d ( ${ songId } ) ' ) ;
continue ;
}
2024-05-11 01:05:51 -04:00
// Only display songs which actually have available difficulties for the current character.
2024-06-18 17:56:24 -04:00
var displayedVariations = song . getVariationsByCharacter ( currentCharacter ) ;
trace ( ' D i s p l a y e d V a r i a t i o n s ( ${ songId } ) : $ displayedVariations ' ) ;
2024-07-28 01:42:09 -04:00
var availableDifficultiesForSong: Array < String > = song . listSuffixedDifficulties ( displayedVariations , false , false ) ;
2024-06-18 17:56:24 -04:00
trace ( ' A v a i l a b l e D i f f i c u l t i e s : $ availableDifficultiesForSong ' ) ;
2024-02-05 21:35:58 -05:00
if ( availableDifficultiesForSong . length == 0 ) continue ;
2023-10-12 03:20:21 -04:00
2024-02-05 21:35:58 -05:00
songs . push ( new FreeplaySongData ( levelId , songId , song , displayedVariations ) ) ;
for ( difficulty in availableDifficultiesForSong )
2023-10-12 03:20:21 -04:00
{
diffIdsTotal . pushUnique ( difficulty ) ;
}
2023-09-28 20:29:19 -04:00
}
}
2021-09-06 14:50:04 -04:00
2023-01-22 19:55:30 -05:00
// LOAD MUSIC
2020-10-21 14:05:27 -04:00
2023-01-22 19:55:30 -05:00
// LOAD CHARACTERS
2020-10-21 14:05:27 -04:00
2023-01-22 19:55:30 -05:00
trace ( FlxG . width ) ;
trace ( FlxG . camera . zoom ) ;
trace ( FlxG . camera . initialZoom ) ;
trace ( FlxCamera . defaultZoom ) ;
2020-10-25 16:51:06 -04:00
2024-03-20 14:37:24 -04:00
pinkBack . color = 0xFFFFD4E9 ; // sets it to pink!
2023-01-22 19:55:30 -05:00
pinkBack . x -= pinkBack . width ;
2021-10-21 23:08:48 -04:00
2023-01-22 19:55:30 -05:00
FlxTween . tween ( pinkBack , { x : 0 } , 0.6 , { ease : FlxEase . quartOut } ) ;
add ( pinkBack ) ;
2021-10-21 23:08:48 -04:00
2023-01-22 19:55:30 -05:00
add ( orangeBackShit ) ;
2021-10-21 23:08:48 -04:00
2023-01-22 19:55:30 -05:00
add ( alsoOrangeLOL ) ;
2021-10-21 23:08:48 -04:00
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ pinkBack , orangeBackShit , alsoOrangeLOL ] ,
{
x : - pinkBack . width ,
y : pinkBack . y ,
speed : 0.4 ,
wait : 0
} ) ;
2023-01-22 19:55:30 -05:00
FlxSpriteUtil . alphaMaskFlxSprite ( orangeBackShit , pinkBack , orangeBackShit ) ;
orangeBackShit . visible = false ;
alsoOrangeLOL . visible = false ;
2021-10-21 23:08:48 -04:00
2024-05-29 23:34:00 -04:00
confirmTextGlow . blend = BlendMode . ADD ;
confirmTextGlow . visible = false ;
confirmGlow . blend = BlendMode . ADD ;
confirmGlow . visible = false ;
confirmGlow2 . visible = false ;
add ( confirmGlow2 ) ;
add ( confirmGlow ) ;
add ( confirmTextGlow ) ;
2023-01-22 19:55:30 -05:00
var grpTxtScrolls: FlxGroup = new FlxGroup ( ) ;
add ( grpTxtScrolls ) ;
grpTxtScrolls . visible = false ;
2021-10-21 23:08:48 -04:00
2024-03-20 14:37:24 -04:00
FlxG . debugger . addTrackerProfile ( new TrackerProfile ( BGScrollingText , [ ' x ' , ' y ' , ' s p e e d ' , ' s i z e ' ] ) ) ;
2023-08-28 14:52:03 -04:00
2024-03-20 14:37:24 -04:00
moreWays . funnyColor = 0xFFFFF383 ;
2023-08-28 14:52:03 -04:00
moreWays . speed = 6.8 ;
2023-01-22 19:55:30 -05:00
grpTxtScrolls . add ( moreWays ) ;
2021-10-21 23:08:48 -04:00
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ moreWays ] ,
2023-03-15 21:05:15 -04:00
{
2023-03-16 01:03:45 -04:00
x : FlxG . width * 2 ,
speed : 0.4 ,
2023-03-15 21:05:15 -04:00
} ) ;
2024-03-20 14:37:24 -04:00
funnyScroll . funnyColor = 0xFFFF9963 ;
2023-08-28 14:52:03 -04:00
funnyScroll . speed = - 3.8 ;
2023-01-22 19:55:30 -05:00
grpTxtScrolls . add ( funnyScroll ) ;
2021-10-21 23:08:48 -04:00
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ funnyScroll ] ,
2023-03-15 21:05:15 -04:00
{
2023-03-16 01:03:45 -04:00
x : - funnyScroll . width * 2 ,
2023-03-15 21:05:15 -04:00
y : funnyScroll . y ,
2023-03-16 01:03:45 -04:00
speed : 0.4 ,
2023-03-15 21:05:15 -04:00
wait : 0
} ) ;
2023-08-28 14:52:03 -04:00
txtNuts . speed = 3.5 ;
2023-01-22 19:55:30 -05:00
grpTxtScrolls . add ( txtNuts ) ;
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ txtNuts ] ,
2023-03-15 21:05:15 -04:00
{
2023-03-16 01:03:45 -04:00
x : FlxG . width * 2 ,
speed : 0.4 ,
2023-03-15 21:05:15 -04:00
} ) ;
2021-10-21 23:08:48 -04:00
2024-03-20 14:37:24 -04:00
funnyScroll2 . funnyColor = 0xFFFF9963 ;
2023-08-28 14:52:03 -04:00
funnyScroll2 . speed = - 3.8 ;
2023-01-22 19:55:30 -05:00
grpTxtScrolls . add ( funnyScroll2 ) ;
2021-10-21 23:08:48 -04:00
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ funnyScroll2 ] ,
2023-03-15 21:05:15 -04:00
{
2023-03-16 01:03:45 -04:00
x : - funnyScroll2 . width * 2 ,
speed : 0.5 ,
2023-03-15 21:05:15 -04:00
} ) ;
2024-03-20 14:37:24 -04:00
moreWays2 . funnyColor = 0xFFFFF383 ;
2023-08-28 14:52:03 -04:00
moreWays2 . speed = 6.8 ;
2023-01-22 19:55:30 -05:00
grpTxtScrolls . add ( moreWays2 ) ;
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ moreWays2 ] ,
2023-03-15 21:05:15 -04:00
{
2023-03-16 01:03:45 -04:00
x : FlxG . width * 2 ,
speed : 0.4
2023-03-15 21:05:15 -04:00
} ) ;
2024-03-20 14:37:24 -04:00
funnyScroll3 . funnyColor = 0xFFFEA400 ;
2023-08-28 14:52:03 -04:00
funnyScroll3 . speed = - 3.8 ;
2023-01-22 19:55:30 -05:00
grpTxtScrolls . add ( funnyScroll3 ) ;
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ funnyScroll3 ] ,
2023-03-15 21:05:15 -04:00
{
2023-03-16 01:03:45 -04:00
x : - funnyScroll3 . width * 2 ,
speed : 0.3
2023-03-15 21:05:15 -04:00
} ) ;
2024-05-29 23:34:00 -04:00
add ( backingTextYeah ) ;
cardGlow . blend = BlendMode . ADD ;
cardGlow . visible = false ;
add ( cardGlow ) ;
2024-06-18 20:07:27 -04:00
if ( currentCharacter ? . getFreeplayDJData ( ) != null )
{
dj = new FreeplayDJ ( 640 , 366 , currentCharacterId ) ;
exitMovers . set ( [ dj ] ,
{
x : - dj . width * 1.6 ,
speed : 0.5
} ) ;
add ( dj ) ;
}
2023-01-22 19:55:30 -05:00
bgDad . shader = new AngleMask ( ) ;
bgDad . visible = false ;
var blackOverlayBullshitLOLXD: FlxSprite = new FlxSprite ( FlxG . width ) . makeGraphic ( Std . int ( bgDad . width ) , Std . int ( bgDad . height ) , FlxColor . BLACK ) ;
add ( blackOverlayBullshitLOLXD ) ; // used to mask the text lol!
2024-06-11 15:57:45 -04:00
// this makes the texture sizes consistent, for the angle shader
bgDad . setGraphicSize ( 0 , FlxG . height ) ;
blackOverlayBullshitLOLXD . setGraphicSize ( 0 , FlxG . height ) ;
bgDad . updateHitbox ( ) ;
blackOverlayBullshitLOLXD . updateHitbox ( ) ;
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ blackOverlayBullshitLOLXD , bgDad ] ,
2023-03-15 21:05:15 -04:00
{
x : FlxG . width * 1.5 ,
2023-03-16 00:17:52 -04:00
speed : 0.4 ,
2023-03-15 21:05:15 -04:00
wait : 0
} ) ;
2023-01-22 19:55:30 -05:00
add ( bgDad ) ;
2024-06-11 15:57:45 -04:00
FlxTween . tween ( blackOverlayBullshitLOLXD , { x : pinkBack . width * 0.74 } , 0.7 , { ease : FlxEase . quintOut } ) ;
2023-01-22 19:55:30 -05:00
blackOverlayBullshitLOLXD . shader = bgDad . shader ;
2024-05-29 23:34:00 -04:00
rankBg . makeSolidColor ( FlxG . width , FlxG . height , 0xD3000000 ) ;
add ( rankBg ) ;
2023-01-22 19:55:30 -05:00
add ( grpSongs ) ;
add ( grpCapsules ) ;
add ( grpDifficulties ) ;
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ grpDifficulties ] ,
{
x : - 300 ,
speed : 0.25 ,
wait : 0
} ) ;
2023-10-12 03:20:21 -04:00
for ( diffId in diffIdsTotal )
{
var diffSprite: DifficultySprite = new DifficultySprite ( diffId ) ;
diffSprite . difficultyId = diffId ;
grpDifficulties . add ( diffSprite ) ;
}
2023-01-22 19:55:30 -05:00
2023-03-15 21:05:15 -04:00
grpDifficulties . group . forEach ( function ( spr ) {
2023-01-22 19:55:30 -05:00
spr . visible = false ;
} ) ;
2023-10-12 03:20:21 -04:00
for ( diffSprite in grpDifficulties . group . members )
{
if ( diffSprite == null ) continue ;
if ( diffSprite . difficultyId == currentDifficulty ) diffSprite . visible = true ;
}
2023-01-22 19:55:30 -05:00
2024-03-28 01:46:50 -04:00
albumRoll . albumId = null ;
2024-03-20 14:37:24 -04:00
add ( albumRoll ) ;
2023-08-09 19:34:19 -04:00
2024-03-20 14:37:24 -04:00
albumRoll . applyExitMovers ( exitMovers ) ;
2023-08-09 19:34:19 -04:00
2023-01-22 19:55:30 -05:00
var overhangStuff: FlxSprite = new FlxSprite ( ) . makeGraphic ( FlxG . width , 64 , FlxColor . BLACK ) ;
overhangStuff . y -= overhangStuff . height ;
add ( overhangStuff ) ;
FlxTween . tween ( overhangStuff , { y : 0 } , 0.3 , { ease : FlxEase . quartOut } ) ;
2024-03-20 14:37:24 -04:00
var fnfFreeplay: FlxText = new FlxText ( 8 , 8 , 0 , ' F R E E P L A Y ' , 48 ) ;
fnfFreeplay . font = ' V C R O S D M o n o ' ;
2023-01-22 19:55:30 -05:00
fnfFreeplay . visible = false ;
2023-03-15 21:05:15 -04:00
2024-03-20 14:37:24 -04:00
ostName . font = ' V C R O S D M o n o ' ;
2024-01-11 00:30:00 -05:00
ostName . alignment = RIGHT ;
ostName . visible = false ;
2024-01-11 00:52:42 -05:00
exitMovers . set ( [ overhangStuff , fnfFreeplay , ostName ] ,
2023-03-15 21:05:15 -04:00
{
2023-03-16 00:17:52 -04:00
y : - overhangStuff . height ,
2023-03-15 21:05:15 -04:00
x : 0 ,
speed : 0.2 ,
wait : 0
} ) ;
2024-03-20 14:37:24 -04:00
var sillyStroke: StrokeShader = new StrokeShader ( 0xFFFFFFFF , 2 , 2 ) ;
2023-01-22 19:55:30 -05:00
fnfFreeplay . shader = sillyStroke ;
2024-04-30 03:22:30 -04:00
ostName . shader = sillyStroke ;
2023-01-22 19:55:30 -05:00
add ( fnfFreeplay ) ;
2024-01-11 00:52:42 -05:00
add ( ostName ) ;
2023-01-22 19:55:30 -05:00
2024-01-11 00:30:00 -05:00
var fnfHighscoreSpr: FlxSprite = new FlxSprite ( 860 , 70 ) ;
2023-01-22 19:55:30 -05:00
fnfHighscoreSpr . frames = Paths . getSparrowAtlas ( ' f r e e p l a y / h i g h s c o r e ' ) ;
2024-03-20 14:37:24 -04:00
fnfHighscoreSpr . animation . addByPrefix ( ' h i g h s c o r e ' , ' h i g h s c o r e s m a l l i n s t a n c e 1 ' , 24 , false ) ;
2023-01-22 19:55:30 -05:00
fnfHighscoreSpr . visible = false ;
fnfHighscoreSpr . setGraphicSize ( 0 , Std . int ( fnfHighscoreSpr . height * 1 ) ) ;
fnfHighscoreSpr . updateHitbox ( ) ;
add ( fnfHighscoreSpr ) ;
2023-03-15 21:05:15 -04:00
new FlxTimer ( ) . start ( FlxG . random . float ( 12 , 50 ) , function ( tmr ) {
2024-03-20 14:37:24 -04:00
fnfHighscoreSpr . animation . play ( ' h i g h s c o r e ' ) ;
2023-01-22 19:55:30 -05:00
tmr . time = FlxG . random . float ( 20 , 60 ) ;
} , 0 ) ;
fp . visible = false ;
add ( fp ) ;
2024-01-11 00:30:00 -05:00
var clearBoxSprite: FlxSprite = new FlxSprite ( 1165 , 65 ) . loadGraphic ( Paths . image ( ' f r e e p l a y / c l e a r B o x ' ) ) ;
2024-04-30 01:33:29 -04:00
clearBoxSprite . visible = false ;
2024-01-11 00:30:00 -05:00
add ( clearBoxSprite ) ;
2023-01-22 19:55:30 -05:00
txtCompletion . visible = false ;
add ( txtCompletion ) ;
2023-08-09 16:15:34 -04:00
add ( letterSort ) ;
letterSort . visible = false ;
exitMovers . set ( [ letterSort ] ,
{
y : - 100 ,
speed : 0.3
} ) ;
letterSort . changeSelectionCallback = ( str ) - > {
switch ( str )
{
2024-03-20 14:37:24 -04:00
c ase ' f a v ' :
2023-08-09 16:15:34 -04:00
generateSongList ( { filterType : FAVORITE } , true ) ;
2024-03-20 14:37:24 -04:00
c ase ' A L L ' :
2023-08-09 19:34:19 -04:00
generateSongList ( null , true ) ;
2024-06-07 13:04:45 -04:00
c ase ' # ' :
generateSongList ( { filterType : REGEXP , filterData : ' 0 - 9 ' } , true ) ;
2023-08-09 16:15:34 -04:00
d efault :
generateSongList ( { filterType : REGEXP , filterData : str } , true ) ;
}
2024-04-29 03:49:28 -04:00
// We want to land on the first song of the group, rather than random song when changing letter sorts
// that is, only if there's more than one song in the group!
if ( grpCapsules . members . length > 0 )
{
2024-06-10 16:13:32 -04:00
FunkinSound . playOnce ( Paths . sound ( ' s c r o l l M e n u ' ) , 0.4 ) ;
2024-04-29 03:49:28 -04:00
curSelected = 1 ;
changeSelection ( ) ;
}
2023-08-09 16:15:34 -04:00
} ;
2024-04-30 01:33:29 -04:00
exitMovers . set ( [ fp , txtCompletion , fnfHighscoreSpr , txtCompletion , clearBoxSprite ] ,
2023-03-16 00:17:52 -04:00
{
x : FlxG . width ,
speed : 0.3
} ) ;
2024-04-24 19:45:17 -04:00
var diffSelLeft: DifficultySelector = new DifficultySelector ( 20 , grpDifficulties . y - 10 , false , controls ) ;
var diffSelRight: DifficultySelector = new DifficultySelector ( 325 , grpDifficulties . y - 10 , true , controls ) ;
diffSelLeft . visible = false ;
diffSelRight . visible = false ;
add ( diffSelLeft ) ;
add ( diffSelRight ) ;
// be careful not to "add()" things in here unless it's to a group that's already added to the state
// otherwise it won't be properly attatched to funnyCamera (relavent code should be at the bottom of create())
2024-06-20 16:17:53 -04:00
var onDJIntroDone = function ( ) {
2023-08-09 19:34:19 -04:00
// when boyfriend hits dat shiii
2023-09-19 23:27:07 -04:00
2024-03-20 14:37:24 -04:00
albumRoll . playIntro ( ) ;
2023-08-09 19:34:19 -04:00
2023-01-22 19:55:30 -05:00
FlxTween . tween ( grpDifficulties , { x : 90 } , 0.6 , { ease : FlxEase . quartOut } ) ;
2024-04-24 19:45:17 -04:00
diffSelLeft . visible = true ;
diffSelRight . visible = true ;
2023-08-09 16:15:34 -04:00
letterSort . visible = true ;
2023-03-16 00:17:52 -04:00
exitMovers . set ( [ diffSelLeft , diffSelRight ] ,
{
x : - diffSelLeft . width * 2 ,
speed : 0.26
} ) ;
2023-01-22 19:55:30 -05:00
2023-03-15 21:05:15 -04:00
new FlxTimer ( ) . start ( 1 / 24 , function ( handShit ) {
2023-01-22 19:55:30 -05:00
fnfHighscoreSpr . visible = true ;
fnfFreeplay . visible = true ;
2024-01-11 00:52:42 -05:00
ostName . visible = true ;
2023-01-22 19:55:30 -05:00
fp . visible = true ;
fp . updateScore ( 0 ) ;
2024-04-30 01:33:29 -04:00
clearBoxSprite . visible = true ;
2023-01-22 19:55:30 -05:00
txtCompletion . visible = true ;
intendedCompletion = 0 ;
2023-03-15 21:05:15 -04:00
new FlxTimer ( ) . start ( 1.5 / 24 , function ( bold ) {
2023-01-22 19:55:30 -05:00
sillyStroke . width = 0 ;
sillyStroke . height = 0 ;
2023-09-19 23:27:07 -04:00
changeSelection ( ) ;
2023-01-22 19:55:30 -05:00
} ) ;
} ) ;
2024-03-20 14:37:24 -04:00
pinkBack . color = 0xFFFFD863 ;
2023-01-22 19:55:30 -05:00
bgDad . visible = true ;
orangeBackShit . visible = true ;
alsoOrangeLOL . visible = true ;
grpTxtScrolls . visible = true ;
2024-05-29 23:34:00 -04:00
2024-05-13 20:20:23 -04:00
// render optimisation
2024-05-23 13:52:28 -04:00
if ( _parentState != null ) _parentState . persistentDraw = false ;
2024-06-07 21:13:13 -04:00
2024-05-29 23:34:00 -04:00
cardGlow . visible = true ;
FlxTween . tween ( cardGlow , { alpha : 0 , " s c a l e . x " : 1.2 , " s c a l e . y " : 1.2 } , 0.45 , { ease : FlxEase . sineOut } ) ;
2024-05-30 05:25:51 -04:00
2024-06-20 16:17:53 -04:00
if ( prepForNewRank && fromResultsParams != null )
2024-05-30 05:25:51 -04:00
{
rankAnimStart ( fromResultsParams ) ;
}
2024-06-20 16:17:53 -04:00
} ;
2024-07-04 14:48:24 -04:00
if ( dj != null )
{
2024-06-20 16:17:53 -04:00
dj . onIntroDone . add ( onDJIntroDone ) ;
2024-07-04 14:48:24 -04:00
}
e lse
{
2024-06-20 16:17:53 -04:00
onDJIntroDone ( ) ;
}
2023-01-22 19:55:30 -05:00
2023-08-09 02:47:22 -04:00
generateSongList ( null , false ) ;
2023-01-22 19:55:30 -05:00
2024-04-24 19:45:17 -04:00
// dedicated camera for the state so we don't need to fuk around with camera scrolls from the mainmenu / elsewhere
2023-01-22 19:55:30 -05:00
funnyCam . bgColor = FlxColor . TRANSPARENT ;
2024-04-24 19:45:17 -04:00
FlxG . cameras . add ( funnyCam , false ) ;
2023-01-22 19:55:30 -05:00
2024-05-29 23:34:00 -04:00
rankVignette . scale . set ( 2 , 2 ) ;
rankVignette . updateHitbox ( ) ;
rankVignette . blend = BlendMode . ADD ;
// rankVignette.cameras = [rankCamera];
add ( rankVignette ) ;
rankVignette . alpha = 0 ;
2023-03-15 21:05:15 -04:00
forEach ( function ( bs ) {
2023-01-22 19:55:30 -05:00
bs . cameras = [ funnyCam ] ;
} ) ;
2024-05-29 23:34:00 -04:00
rankCamera . bgColor = FlxColor . TRANSPARENT ;
FlxG . cameras . add ( rankCamera , false ) ;
rankBg . cameras = [ rankCamera ] ;
rankBg . alpha = 0 ;
2024-05-31 05:39:53 -04:00
2024-06-02 02:53:07 -04:00
if ( prepForNewRank )
2024-05-31 05:39:53 -04:00
{
rankCamera . fade ( 0xFF000000 , 0 , false , null , true ) ;
}
2023-01-22 19:55:30 -05:00
}
2024-06-20 16:17:53 -04:00
var currentFilter: Null < SongFilter > = null ;
var currentFilteredSongs: Array < Null < FreeplaySongData > > = [ ] ;
2024-04-01 18:34:26 -04:00
2024-03-20 14:37:24 -04:00
/ * *
* Given the current filter , rebuild the current song list .
*
* @ param filterStuff A filter to apply to the song list ( regex , startswith , all , favorite )
2024-04-16 22:12:07 -04:00
* @ param force Whether the capsules should " j u m p " back in or not using their animation
2024-04-01 18:34:26 -04:00
* @ param onlyIfChanged Only apply the filter if t h e s o n g l i s t h a s c h a n g e d
2024-03-20 14:37:24 -04:00
* /
2024-04-01 18:34:26 -04:00
public function generateSongList ( filterStuff : Null < SongFilter > , force : Bool = false , onlyIfChanged : Bool = true ) : Void
2023-01-22 19:55:30 -05:00
{
2024-06-20 16:17:53 -04:00
var tempSongs: Array < Null < FreeplaySongData > > = songs ;
2023-01-22 19:55:30 -05:00
2024-04-30 14:36:57 -04:00
// Remember just the difficulty because it's important for song sorting.
if ( rememberedDifficulty != null )
{
currentDifficulty = rememberedDifficulty ;
}
2024-04-16 22:12:07 -04:00
if ( filterStuff != null ) tempSongs = sortSongs ( tempSongs , filterStuff ) ;
2023-01-22 19:55:30 -05:00
2024-04-01 18:34:26 -04:00
// Filter further by current selected difficulty.
if ( currentDifficulty != null )
{
tempSongs = tempSongs . filter ( song - > {
if ( song == null ) return true ; // Random
return song . songDifficulties . contains ( currentDifficulty ) ;
} ) ;
}
if ( onlyIfChanged )
{
// == performs equality by reference
if ( tempSongs . isEqualUnordered ( currentFilteredSongs ) ) return ;
}
// Only now do we know that the filter is actually changing.
2024-04-30 14:36:57 -04:00
// If curSelected is 0, the result will be null and fall back to the rememberedSongId.
2024-04-03 01:40:08 -04:00
rememberedSongId = grpCapsules . members [ curSelected ] ? . songData ? . songId ? ? rememberedSongId ;
2024-04-01 18:34:26 -04:00
for ( cap in grpCapsules . members )
{
2024-05-29 23:34:00 -04:00
cap . songText . resetText ( ) ;
2024-04-01 18:34:26 -04:00
cap . kill ( ) ;
}
currentFilter = filterStuff ;
currentFilteredSongs = tempSongs ;
curSelected = 0 ;
2023-08-28 14:52:03 -04:00
var hsvShader: HSVShader = new HSVShader ( ) ;
2023-08-09 02:47:22 -04:00
var randomCapsule: SongMenuItem = grpCapsules . recycle ( SongMenuItem ) ;
2023-10-16 20:12:40 -04:00
randomCapsule . init ( FlxG . width , 0 , null ) ;
2023-08-06 16:24:34 -04:00
randomCapsule . onConfirm = function ( ) {
2023-10-17 00:38:28 -04:00
capsuleOnConfirmRandom ( randomCapsule ) ;
2023-08-06 16:24:34 -04:00
} ;
randomCapsule . y = randomCapsule . intendedY ( 0 ) + 10 ;
randomCapsule . targetPos . x = randomCapsule . x ;
2024-05-29 23:34:00 -04:00
randomCapsule . alpha = 0 ;
2023-08-06 16:24:34 -04:00
randomCapsule . songText . visible = false ;
randomCapsule . favIcon . visible = false ;
2024-06-04 23:36:32 -04:00
randomCapsule . favIconBlurred . visible = false ;
2024-05-29 23:34:00 -04:00
randomCapsule . ranking . visible = false ;
randomCapsule . blurredRanking . visible = false ;
2023-08-06 16:24:34 -04:00
randomCapsule . initJumpIn ( 0 , force ) ;
2023-08-28 14:52:03 -04:00
randomCapsule . hsvShader = hsvShader ;
2023-08-06 16:24:34 -04:00
grpCapsules . add ( randomCapsule ) ;
2023-01-22 19:55:30 -05:00
for ( i in 0 ... tempSongs . length )
{
2024-06-20 16:17:53 -04:00
var tempSong = tempSongs [ i ] ;
if ( tempSong == null ) continue ;
2023-10-10 23:32:01 -04:00
2023-08-09 02:47:22 -04:00
var funnyMenu: SongMenuItem = grpCapsules . recycle ( SongMenuItem ) ;
2023-10-10 23:32:01 -04:00
2024-06-20 16:17:53 -04:00
funnyMenu . init ( FlxG . width , 0 , tempSong ) ;
2023-09-28 20:29:19 -04:00
funnyMenu . onConfirm = function ( ) {
capsuleOnConfirmDefault ( funnyMenu ) ;
} ;
2023-08-04 17:10:27 -04:00
funnyMenu . y = funnyMenu . intendedY ( i + 1 ) + 10 ;
2023-01-22 19:55:30 -05:00
funnyMenu . targetPos . x = funnyMenu . x ;
funnyMenu . ID = i ;
2023-09-19 19:10:30 -04:00
funnyMenu . capsule . alpha = 0.5 ;
2023-01-22 19:55:30 -05:00
funnyMenu . songText . visible = false ;
2024-06-20 16:17:53 -04:00
funnyMenu . favIcon . visible = tempSong . isFav ;
funnyMenu . favIconBlurred . visible = tempSong . isFav ;
2023-08-28 14:52:03 -04:00
funnyMenu . hsvShader = hsvShader ;
2023-01-22 19:55:30 -05:00
2024-05-29 23:34:00 -04:00
funnyMenu . newText . animation . curAnim . curFrame = 45 - ( ( i * 4 ) % 45 ) ;
funnyMenu . checkClip ( ) ;
2024-06-02 02:53:07 -04:00
funnyMenu . forcePosition ( ) ;
2024-05-29 23:34:00 -04:00
2023-01-22 19:55:30 -05:00
grpCapsules . add ( funnyMenu ) ;
}
2024-03-20 14:37:24 -04:00
FlxG . console . registerFunction ( ' c h a n g e S e l e c t i o n ' , changeSelection ) ;
2023-09-19 23:27:07 -04:00
2023-10-12 03:20:21 -04:00
rememberSelection ( ) ;
2023-01-22 19:55:30 -05:00
changeSelection ( ) ;
2024-04-30 14:36:57 -04:00
changeDiff ( 0 , true ) ;
2023-01-22 19:55:30 -05:00
}
2024-04-16 22:12:07 -04:00
/ * *
* Filters an array of songs based on a filter
* @ param songsToFilter What data to use when filtering
* @ param songFilter The filter to apply
* @ return Array < FreeplaySongData >
* /
2024-06-20 16:17:53 -04:00
public function sortSongs ( songsToFilter : Array < Null < FreeplaySongData > > , songFilter : SongFilter ) : Array < Null < FreeplaySongData > >
2024-04-16 22:12:07 -04:00
{
2024-06-20 16:17:53 -04:00
var filterAlphabetically = function ( a : Null < FreeplaySongData > , b : Null < FreeplaySongData > ) : Int {
return SortUtil . alphabetically ( a ? . songName ? ? ' ' , b ? . s o n g N a m e ? ? ' ' ) ;
2024-06-04 16:24:24 -04:00
} ;
2024-04-16 22:12:07 -04:00
switch ( songFilter . filterType )
{
c ase REGEXP :
// filterStuff.filterData has a string with the first letter of the sorting range, and the second one
// this creates a filter to return all the songs that start with a letter between those two
// if filterData looks like "A-C", the regex should look something like this: ^[A-C].*
// to get every song that starts between A and C
var filterRegexp: EReg = new EReg ( ' ^ [ ' + songFilter . filterData + ' ] . * ' , ' i ' ) ;
songsToFilter = songsToFilter . filter ( str - > {
if ( str == null ) return true ; // Random
return filterRegexp . match ( str . songName ) ;
} ) ;
2024-06-04 16:24:24 -04:00
songsToFilter . sort ( filterAlphabetically ) ;
2024-04-16 22:12:07 -04:00
c ase STARTSWITH :
// extra note: this is essentially a "search"
songsToFilter = songsToFilter . filter ( str - > {
if ( str == null ) return true ; // Random
2024-06-20 16:17:53 -04:00
return str . songName . toLowerCase ( ) . startsWith ( songFilter . filterData ? ? ' ' ) ;
2024-04-16 22:12:07 -04:00
} ) ;
c ase ALL :
// no filter!
c ase FAVORITE :
songsToFilter = songsToFilter . filter ( str - > {
if ( str == null ) return true ; // Random
return str . isFav ;
} ) ;
2024-06-04 16:24:24 -04:00
songsToFilter . sort ( filterAlphabetically ) ;
2024-04-16 22:12:07 -04:00
d efault :
// return all on default
}
2024-06-04 16:24:24 -04:00
2024-04-16 22:12:07 -04:00
return songsToFilter ;
}
2024-06-01 19:25:52 -04:00
var sparks: FlxSprite ;
var sparksADD: FlxSprite ;
2024-06-20 16:17:53 -04:00
function rankAnimStart ( fromResults : FromResultsParams ) : Void
2024-05-29 23:34:00 -04:00
{
2024-05-30 05:25:51 -04:00
busy = true ;
2024-06-05 20:49:33 -04:00
grpCapsules . members [ curSelected ] . sparkle . alpha = 0 ;
2024-05-31 05:39:53 -04:00
// grpCapsules.members[curSelected].forcePosition();
2024-05-30 05:25:51 -04:00
2024-06-20 16:17:53 -04:00
rememberedSongId = fromResults . songId ;
rememberedDifficulty = fromResults . difficultyId ;
changeSelection ( ) ;
changeDiff ( ) ;
2024-06-01 22:36:47 -04:00
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . fistPump ( ) ;
2024-05-29 23:34:00 -04:00
// rankCamera.fade(FlxColor.BLACK, 0.5, true);
rankCamera . fade ( 0xFF000000 , 0.5 , true , null , true ) ;
2024-05-31 02:30:42 -04:00
if ( FlxG . sound . music != null ) FlxG . sound . music . volume = 0 ;
2024-05-29 23:34:00 -04:00
rankBg . alpha = 1 ;
2024-06-20 16:17:53 -04:00
if ( fromResults . oldRank != null )
2024-06-01 19:25:52 -04:00
{
grpCapsules . members [ curSelected ] . fakeRanking . rank = fromResults . oldRank ;
grpCapsules . members [ curSelected ] . fakeBlurredRanking . rank = fromResults . oldRank ;
sparks . frames = Paths . getSparrowAtlas ( ' f r e e p l a y / s p a r k s ' ) ;
sparks . animation . addByPrefix ( ' s p a r k s ' , ' s p a r k s ' , 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 . visible = false ;
sparksADD . frames = Paths . getSparrowAtlas ( ' f r e e p l a y / s p a r k s a d d ' ) ;
sparksADD . animation . addByPrefix ( ' s p a r k s a d d ' , ' s p a r k s a d d ' , 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 )
{
c ase SHIT :
sparksADD . color = 0xFF6044FF ;
c ase GOOD :
sparksADD . color = 0xFFEF8764 ;
c ase GREAT :
sparksADD . color = 0xFFEAF6FF ;
c ase EXCELLENT :
sparksADD . color = 0xFFFDCB42 ;
c ase PERFECT :
sparksADD . color = 0xFFFF58B4 ;
c ase PERFECT_GOLD :
sparksADD . color = 0xFFFFB619 ;
}
// sparksADD.color = sparks.color;
}
2024-05-31 05:39:53 -04:00
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 ) ;
2024-05-29 23:34:00 -04:00
2024-06-01 19:25:52 -04:00
grpCapsules . members [ curSelected ] . ranking . visible = false ;
grpCapsules . members [ curSelected ] . blurredRanking . visible = false ;
2024-05-29 23:34:00 -04:00
rankCamera . zoom = 1.85 ;
FlxTween . tween ( rankCamera , { " z o o m " : 1.8 } , 0.6 , { ease : FlxEase . sineIn } ) ;
funnyCam . zoom = 1.15 ;
FlxTween . tween ( funnyCam , { " z o o m " : 1.1 } , 0.6 , { ease : FlxEase . sineIn } ) ;
grpCapsules . members [ curSelected ] . cameras = [ rankCamera ] ;
2024-05-31 05:39:53 -04:00
// 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 ) ,
2024-05-29 23:34:00 -04:00
( FlxG . height / 2 ) - ( grpCapsules . members [ curSelected ] . height / 2 ) ) ;
new FlxTimer ( ) . start ( 0.5 , _ - > {
2024-05-30 05:25:51 -04:00
rankDisplayNew ( fromResults ) ;
2024-05-29 23:34:00 -04:00
} ) ;
}
2024-05-30 05:25:51 -04:00
function rankDisplayNew ( fromResults : Null < FromResultsParams > ) : Void
2024-05-29 23:34:00 -04:00
{
2024-06-01 19:25:52 -04:00
grpCapsules . members [ curSelected ] . ranking . visible = true ;
grpCapsules . members [ curSelected ] . blurredRanking . visible = true ;
2024-05-29 23:34:00 -04:00
grpCapsules . members [ curSelected ] . ranking . scale . set ( 20 , 20 ) ;
grpCapsules . members [ curSelected ] . blurredRanking . scale . set ( 20 , 20 ) ;
2024-06-20 16:17:53 -04:00
if ( fromResults != null && fromResults . newRank != null )
2024-06-11 15:57:45 -04:00
{
2024-06-09 02:22:03 -04:00
grpCapsules . members [ curSelected ] . ranking . animation . play ( fromResults . newRank . getFreeplayRankIconAsset ( ) , true ) ;
}
2024-05-30 05:25:51 -04:00
2024-05-29 23:34:00 -04:00
FlxTween . tween ( grpCapsules . members [ curSelected ] . ranking , { " s c a l e . x " : 1 , " s c a l e . y " : 1 } , 0.1 ) ;
2024-06-20 16:17:53 -04:00
if ( fromResults != null && fromResults . newRank != null )
2024-06-11 15:57:45 -04:00
{
2024-06-09 02:22:03 -04:00
grpCapsules . members [ curSelected ] . blurredRanking . animation . play ( fromResults . newRank . getFreeplayRankIconAsset ( ) , true ) ;
}
2024-05-29 23:34:00 -04:00
FlxTween . tween ( grpCapsules . members [ curSelected ] . blurredRanking , { " s c a l e . x " : 1 , " s c a l e . y " : 1 } , 0.1 ) ;
new FlxTimer ( ) . start ( 0.1 , _ - > {
2024-06-01 19:25:52 -04:00
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 ( ' s p a r k s ' , true ) ;
sparksADD . animation . play ( ' s p a r k s a d d ' , true ) ;
sparks . animation . finishCallback = anim - > {
sparks . visible = false ;
sparksADD . visible = false ;
} ;
}
2024-05-30 05:25:51 -04:00
switch ( fromResultsParams ? . newRank )
2024-05-29 23:34:00 -04:00
{
2024-05-30 05:25:51 -04:00
c ase SHIT :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / r a n k i n b a d ' ) ) ;
2024-05-30 05:25:51 -04:00
c ase PERFECT :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / r a n k i n p e r f e c t ' ) ) ;
2024-05-30 05:25:51 -04:00
c ase PERFECT_GOLD :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / r a n k i n p e r f e c t ' ) ) ;
d efault :
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / r a n k i n n o r m a l ' ) ) ;
}
rankCamera . zoom = 1.3 ;
FlxTween . tween ( rankCamera , { " z o o m " : 1.5 } , 0.3 , { ease : FlxEase . backInOut } ) ;
grpCapsules . members [ curSelected ] . x -= 10 ;
grpCapsules . members [ curSelected ] . y -= 20 ;
FlxTween . tween ( funnyCam , { " z o o m " : 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 , { " z o o m " : 1 } , 0.8 , { ease : FlxEase . sineIn } ) ;
FlxTween . tween ( rankCamera , { " z o o m " : 1.2 } , 0.8 , { ease : FlxEase . backIn } ) ;
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 , _ - > {
2024-05-30 05:25:51 -04:00
rankAnimSlam ( fromResults ) ;
2024-05-29 23:34:00 -04:00
} ) ;
}
2024-05-30 05:25:51 -04:00
function rankAnimSlam ( fromResultsParams : Null < FromResultsParams > )
2024-05-29 23:34:00 -04:00
{
// 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});
2024-05-30 05:25:51 -04:00
switch ( fromResultsParams ? . newRank )
2024-05-29 23:34:00 -04:00
{
2024-05-30 05:25:51 -04:00
c ase SHIT :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / l o s s ' ) ) ;
2024-05-30 05:25:51 -04:00
c ase GOOD :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / g o o d ' ) ) ;
2024-05-30 05:25:51 -04:00
c ase GREAT :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / g r e a t ' ) ) ;
2024-05-30 05:25:51 -04:00
c ase EXCELLENT :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / e x c e l l e n t ' ) ) ;
2024-05-30 05:25:51 -04:00
c ase PERFECT :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / p e r f e c t ' ) ) ;
2024-05-30 05:25:51 -04:00
c ase PERFECT_GOLD :
2024-05-29 23:34:00 -04:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / p e r f e c t ' ) ) ;
d efault :
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / l o s s ' ) ) ;
}
FlxTween . tween ( grpCapsules . members [ curSelected ] , { " t a r g e t P o s . x " : originalPos . x , " t a r g e t P o s . y " : originalPos . y } , 0.5 , { ease : FlxEase . expoOut } ) ;
new FlxTimer ( ) . start ( 0.5 , _ - > {
funnyCam . shake ( 0.0045 , 0.35 ) ;
2024-05-30 05:25:51 -04:00
if ( fromResultsParams ? . newRank == SHIT )
2024-05-29 23:34:00 -04:00
{
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . pumpFistBad ( ) ;
2024-05-29 23:34:00 -04:00
}
e lse
{
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . pumpFist ( ) ;
2024-05-29 23:34:00 -04:00
}
rankCamera . zoom = 0.8 ;
funnyCam . zoom = 0.8 ;
FlxTween . tween ( rankCamera , { " z o o m " : 1 } , 1 , { ease : FlxEase . elasticOut } ) ;
FlxTween . tween ( funnyCam , { " z o o m " : 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 ] ;
2024-05-30 05:25:51 -04:00
// NOW we can interact with the menu
busy = false ;
2024-07-28 01:42:09 -04:00
capsule . sparkle . alpha = 0.7 ;
2024-06-05 20:49:33 -04:00
playCurSongPreview ( capsule ) ;
2024-05-29 23:34:00 -04:00
} , 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();
2024-05-31 05:39:53 -04:00
prepForNewRank = false ;
2024-05-29 23:34:00 -04:00
} ) ;
}
2023-01-22 19:55:30 -05:00
var touchY: Float = 0 ;
var touchX: Float = 0 ;
var dxTouch: Float = 0 ;
var dyTouch: Float = 0 ;
var velTouch: Float = 0 ;
var veloctiyLoopShit: Float = 0 ;
var touchTimer: Float = 0 ;
var initTouchPos: FlxPoint = new FlxPoint ( ) ;
var spamTimer: Float = 0 ;
var spamming: Bool = false ;
2024-05-30 05:25:51 -04:00
/ * *
* If true , disable interaction with the interface .
* /
var busy: Bool = false ;
2023-10-17 00:38:28 -04:00
2024-05-29 23:34:00 -04:00
var originalPos: FlxPoint = new FlxPoint ( ) ;
2024-03-11 23:42:32 -04:00
override function update ( elapsed : Float ) : Void
2023-01-22 19:55:30 -05:00
{
super . update ( elapsed ) ;
2024-05-30 05:25:51 -04:00
#if debug
2024-05-29 23:34:00 -04:00
if ( FlxG . keys . justPressed . T )
{
2024-06-20 16:17:53 -04:00
rankAnimStart ( fromResultsParams ? ?
{
playRankAnim : true ,
newRank : PERFECT_GOLD ,
songId : " t u t o r i a l " ,
difficultyId : " h a r d "
} ) ;
2024-05-29 23:34:00 -04:00
}
2024-06-18 17:56:24 -04:00
if ( FlxG . keys . justPressed . P )
{
FlxG . switchState ( FreeplayState . build (
{
{
character : currentCharacterId == " p i c o " ? " b f " : " p i c o " ,
}
} ) ) ;
2024-05-29 23:34:00 -04:00
}
2024-06-01 19:25:52 -04:00
// if (FlxG.keys.justPressed.H)
// {
// rankDisplayNew(fromResultsParams);
// }
// if (FlxG.keys.justPressed.G)
// {
// rankAnimSlam(fromResultsParams);
// }
2024-05-30 05:25:51 -04:00
#end
2024-05-29 23:34:00 -04:00
2024-07-08 16:40:10 -04:00
if ( controls . FREEPLAY_CHAR_SELECT && ! busy )
2024-07-08 16:22:38 -04:00
{
FlxG . switchState ( new funkin . ui . charSelect . CharSelectSubState ( ) ) ;
}
2024-06-09 02:22:03 -04:00
if ( controls . FREEPLAY_FAVORITE && ! busy )
2023-01-22 19:55:30 -05:00
{
2024-04-01 18:34:26 -04:00
var targetSong = grpCapsules . members [ curSelected ] ? . songData ;
if ( targetSong != null )
2023-01-22 19:55:30 -05:00
{
2024-03-20 14:37:24 -04:00
var realShit: Int = curSelected ;
2024-05-21 02:49:07 -04:00
var isFav = targetSong . toggleFavorite ( ) ;
if ( isFav )
2023-10-10 23:32:01 -04:00
{
2024-05-31 05:39:53 -04:00
grpCapsules . members [ realShit ] . favIcon . visible = true ;
2024-06-04 23:36:32 -04:00
grpCapsules . members [ realShit ] . favIconBlurred . visible = true ;
2024-05-31 05:39:53 -04:00
grpCapsules . members [ realShit ] . favIcon . animation . play ( ' f a v ' ) ;
2024-06-04 23:36:32 -04:00
grpCapsules . members [ realShit ] . favIconBlurred . animation . play ( ' f a v ' ) ;
2024-05-31 05:39:53 -04:00
FunkinSound . playOnce ( Paths . sound ( ' f a v ' ) , 1 ) ;
2024-06-02 02:53:07 -04:00
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
2024-05-31 05:39:53 -04:00
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 ,
2023-10-10 23:32:01 -04:00
{
2024-05-31 05:39:53 -04:00
ease : FlxEase . expoIn ,
startDelay : 0.1 ,
onComplete : function ( _ ) {
grpCapsules . members [ realShit ] . doLerp = true ;
busy = false ;
2023-10-10 23:32:01 -04:00
}
} ) ;
}
e lse
{
2024-05-31 05:39:53 -04:00
grpCapsules . members [ realShit ] . favIcon . animation . play ( ' f a v ' , true , true , 9 ) ;
2024-06-04 23:36:32 -04:00
grpCapsules . members [ realShit ] . favIconBlurred . animation . play ( ' f a v ' , true , true , 9 ) ;
2024-05-31 05:39:53 -04:00
FunkinSound . playOnce ( Paths . sound ( ' u n f a v ' ) , 1 ) ;
new FlxTimer ( ) . start ( 0.2 , _ - > {
2023-10-10 23:32:01 -04:00
grpCapsules . members [ realShit ] . favIcon . visible = false ;
2024-06-04 23:36:32 -04:00
grpCapsules . members [ realShit ] . favIconBlurred . visible = false ;
2024-06-02 02:53:07 -04:00
grpCapsules . members [ realShit ] . checkClip ( ) ;
2023-01-22 22:25:45 -05:00
} ) ;
2024-05-31 05:39:53 -04:00
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 ;
}
} ) ;
2023-10-10 23:32:01 -04:00
}
2023-01-22 19:55:30 -05:00
}
}
2024-05-08 01:54:48 -04:00
lerpScore = MathUtil . smoothLerp ( lerpScore , intendedScore , elapsed , 0.5 ) ;
lerpCompletion = MathUtil . smoothLerp ( lerpCompletion , intendedCompletion , elapsed , 0.5 ) ;
2023-01-22 19:55:30 -05:00
2024-01-11 00:30:00 -05:00
if ( Math . isNaN ( lerpScore ) )
{
lerpScore = intendedScore ;
}
if ( Math . isNaN ( lerpCompletion ) )
{
lerpCompletion = intendedCompletion ;
}
2023-01-22 19:55:30 -05:00
fp . updateScore ( Std . int ( lerpScore ) ) ;
2024-01-11 00:30:00 -05:00
txtCompletion . text = ' ${ Math . floor ( lerpCompletion * 100 ) } ' ;
// Right align the completion percentage
switch ( txtCompletion . text . length )
{
c ase 3 :
2024-04-30 01:33:29 -04:00
txtCompletion . offset . x = 10 ;
2024-01-11 00:30:00 -05:00
c ase 2 :
2024-04-30 01:33:29 -04:00
txtCompletion . offset . x = 0 ;
2024-01-11 00:30:00 -05:00
c ase 1 :
2024-04-30 01:33:29 -04:00
txtCompletion . offset . x = - 24 ;
2024-01-11 00:30:00 -05:00
d efault :
2024-04-30 01:33:29 -04:00
txtCompletion . offset . x = 0 ;
2024-01-11 00:30:00 -05:00
}
2023-01-22 19:55:30 -05:00
2023-10-17 00:38:28 -04:00
handleInputs ( elapsed ) ;
}
function handleInputs ( elapsed : Float ) : Void
{
if ( busy ) return ;
2023-01-22 19:55:30 -05:00
2024-06-18 17:56:24 -04:00
var upP: Bool = controls . UI_UP_P ;
var downP: Bool = controls . UI_DOWN_P ;
var accepted: Bool = controls . ACCEPT ;
2023-01-22 19:55:30 -05:00
if ( FlxG . onMobile )
{
for ( touch in FlxG . touches . list )
{
if ( touch . justPressed )
{
initTouchPos . set ( touch . screenX , touch . screenY ) ;
}
if ( touch . pressed )
{
2024-03-20 14:37:24 -04:00
var dx: Float = initTouchPos . x - touch . screenX ;
var dy: Float = initTouchPos . y - touch . screenY ;
2023-01-22 19:55:30 -05:00
2024-03-20 14:37:24 -04:00
var angle: Float = Math . atan2 ( dy , dx ) ;
var length: Float = Math . sqrt ( dx * dx + dy * dy ) ;
2023-01-22 19:55:30 -05:00
2024-03-20 14:37:24 -04:00
FlxG . watch . addQuick ( ' L E N G T H ' , length ) ;
FlxG . watch . addQuick ( ' A N G L E ' , Math . round ( FlxAngle . asDegrees ( angle ) ) ) ;
2023-01-22 19:55:30 -05:00
}
}
if ( FlxG . touches . getFirst ( ) != null )
{
2023-01-22 22:25:45 -05:00
if ( touchTimer >= 1.5 ) accepted = true ;
2023-01-22 19:55:30 -05:00
touchTimer += elapsed ;
var touch: FlxTouch = FlxG . touches . getFirst ( ) ;
velTouch = Math . abs ( ( touch . screenY - dyTouch ) ) / 50 ;
dyTouch = touch . screenY - touchY ;
dxTouch = touch . screenX - touchX ;
if ( touch . justPressed )
{
touchY = touch . screenY ;
dyTouch = 0 ;
velTouch = 0 ;
touchX = touch . screenX ;
dxTouch = 0 ;
}
if ( Math . abs ( dxTouch ) >= 100 )
{
touchX = touch . screenX ;
2023-01-22 22:25:45 -05:00
if ( dxTouch != 0 ) dxTouch < 0 ? changeDiff ( 1 ) : changeDiff ( - 1 ) ;
2023-01-22 19:55:30 -05:00
}
if ( Math . abs ( dyTouch ) >= 100 )
{
touchY = touch . screenY ;
2023-01-22 22:25:45 -05:00
if ( dyTouch != 0 ) dyTouch < 0 ? changeSelection ( 1 ) : changeSelection ( - 1 ) ;
2023-01-22 19:55:30 -05:00
}
}
e lse
{
touchTimer = 0 ;
}
}
#if mobile
for ( touch in FlxG . touches . list )
{
if ( touch . justPressed )
{
// accepted = true;
}
}
#end
2024-06-18 17:56:24 -04:00
if ( ( controls . UI_UP || controls . UI_DOWN ) )
2023-01-22 19:55:30 -05:00
{
if ( spamming )
{
if ( spamTimer >= 0.07 )
{
spamTimer = 0 ;
2024-03-20 14:37:24 -04:00
if ( controls . UI_UP )
{
changeSelection ( - 1 ) ;
}
2023-01-22 19:55:30 -05:00
e lse
2024-03-20 14:37:24 -04:00
{
2023-01-22 19:55:30 -05:00
changeSelection ( 1 ) ;
2024-03-20 14:37:24 -04:00
}
2023-01-22 19:55:30 -05:00
}
}
2024-03-24 04:53:05 -04:00
e lse if ( spamTimer >= 0.9 )
{
spamming = true ;
}
e lse if ( spamTimer <= 0 )
{
if ( controls . UI_UP )
{
changeSelection ( - 1 ) ;
}
e lse
{
changeSelection ( 1 ) ;
}
}
spamTimer += elapsed ;
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2023-01-22 19:55:30 -05:00
}
e lse
{
spamming = false ;
spamTimer = 0 ;
}
2024-05-11 20:21:59 -04:00
#if ! html5
2023-01-22 19:55:30 -05:00
if ( FlxG . mouse . wheel != 0 )
{
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2024-05-11 19:35:04 -04:00
changeSelection ( - Math . round ( FlxG . mouse . wheel ) ) ;
2023-01-22 19:55:30 -05:00
}
2024-05-11 20:21:59 -04:00
#else
if ( FlxG . mouse . wheel < 0 )
{
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2024-05-14 21:21:47 -04:00
changeSelection ( - Math . round ( FlxG . mouse . wheel / 8 ) ) ;
2023-01-22 19:55:30 -05:00
}
2024-05-11 20:21:59 -04:00
e lse if ( FlxG . mouse . wheel > 0 )
{
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2024-05-11 20:21:59 -04:00
changeSelection ( - Math . round ( FlxG . mouse . wheel / 8 ) ) ;
}
#end
2023-01-22 19:55:30 -05:00
2024-06-18 17:56:24 -04:00
if ( controls . UI_LEFT_P )
2023-01-22 19:55:30 -05:00
{
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2023-01-22 19:55:30 -05:00
changeDiff ( - 1 ) ;
2024-04-01 18:34:26 -04:00
generateSongList ( currentFilter , true ) ;
2023-01-22 19:55:30 -05:00
}
2024-06-18 17:56:24 -04:00
if ( controls . UI_RIGHT_P )
2023-01-22 19:55:30 -05:00
{
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2023-01-22 19:55:30 -05:00
changeDiff ( 1 ) ;
2024-04-01 18:34:26 -04:00
generateSongList ( currentFilter , true ) ;
2023-01-22 19:55:30 -05:00
}
2024-05-02 21:23:55 -04:00
if ( controls . BACK )
2023-01-22 19:55:30 -05:00
{
2024-05-11 20:42:02 -04:00
busy = true ;
2023-03-16 22:02:56 -04:00
FlxTween . globalManager . clear ( ) ;
FlxTimer . globalManager . clear ( ) ;
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . onIntroDone . removeAll ( ) ;
2023-03-16 22:02:56 -04:00
2024-03-23 17:50:48 -04:00
FunkinSound . playOnce ( Paths . sound ( ' c a n c e l M e n u ' ) ) ;
2023-01-22 19:55:30 -05:00
2023-03-15 21:05:15 -04:00
var longestTimer: Float = 0 ;
2024-05-31 05:39:53 -04:00
// 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 , " s c a l e . x " : 1.2 , " s c a l e . 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 ;
2023-03-16 00:17:52 -04:00
for ( grpSpr in exitMovers . keys ( ) )
2023-03-15 21:05:15 -04:00
{
2024-06-20 16:17:53 -04:00
var moveData: Null < MoveData > = exitMovers . get ( grpSpr ) ;
if ( moveData == null ) continue ;
2023-03-16 00:17:52 -04:00
for ( spr in grpSpr )
{
2024-03-28 01:46:50 -04:00
if ( spr == null ) continue ;
2023-03-16 00:17:52 -04:00
var funnyMoveShit: MoveData = moveData ;
2024-06-20 16:17:53 -04:00
var moveDataX = funnyMoveShit . x ? ? spr . x ;
var moveDataY = funnyMoveShit . y ? ? spr . y ;
var moveDataSpeed = funnyMoveShit . speed ? ? 0.2 ;
2024-07-29 17:26:49 -04:00
var moveDataWait = funnyMoveShit . wait ? ? 0.0 ;
2023-03-15 21:05:15 -04:00
2024-06-20 16:17:53 -04:00
FlxTween . tween ( spr , { x : moveDataX , y : moveDataY } , moveDataSpeed , { ease : FlxEase . expoIn } ) ;
2023-03-16 00:17:52 -04:00
2024-06-20 16:17:53 -04:00
longestTimer = Math . max ( longestTimer , moveDataSpeed + moveDataWait ) ;
2023-03-16 00:17:52 -04:00
}
2023-03-15 21:05:15 -04:00
}
for ( caps in grpCapsules . members )
{
caps . doJumpIn = false ;
caps . doLerp = false ;
caps . doJumpOut = true ;
}
2024-04-30 13:58:39 -04:00
if ( Type . getClass ( _parentState ) == MainMenuState )
2023-03-16 00:55:25 -04:00
{
2024-04-30 13:58:39 -04:00
_parentState . persistentUpdate = false ;
_parentState . persistentDraw = true ;
2023-03-16 00:55:25 -04:00
}
2023-03-15 21:05:15 -04:00
new FlxTimer ( ) . start ( longestTimer , ( _ ) - > {
FlxTransitionableState . skipNextTransIn = true ;
FlxTransitionableState . skipNextTransOut = true ;
2024-04-30 13:58:39 -04:00
if ( Type . getClass ( _parentState ) == MainMenuState )
2023-03-16 00:17:52 -04:00
{
2024-04-03 01:40:08 -04:00
FunkinSound . playMusic ( ' f r e a k y M e n u ' ,
{
overrideExisting : true ,
restartTrack : false
} ) ;
2024-06-01 20:36:14 -04:00
FlxG . sound . music . fadeIn ( 4.0 , 0.0 , 1.0 ) ;
2023-03-16 00:17:52 -04:00
close ( ) ;
}
e lse
{
2024-02-05 21:35:58 -05:00
FlxG . switchState ( ( ) - > new MainMenuState ( ) ) ;
2023-03-16 00:17:52 -04:00
}
2023-03-15 21:05:15 -04:00
} ) ;
2023-01-22 19:55:30 -05:00
}
if ( accepted )
{
2023-08-06 16:24:34 -04:00
grpCapsules . members [ curSelected ] . onConfirm ( ) ;
2023-01-22 19:55:30 -05:00
}
}
2023-12-15 21:09:01 -05:00
public override function destroy ( ) : Void
2023-01-22 19:55:30 -05:00
{
2023-12-15 21:09:01 -05:00
super . destroy ( ) ;
2024-04-03 01:01:58 -04:00
var daSong: Null < FreeplaySongData > = currentFilteredSongs [ curSelected ] ;
2023-10-10 23:32:01 -04:00
if ( daSong != null )
{
clearDaCache ( daSong . songName ) ;
}
2024-05-13 20:20:23 -04:00
// remove and destroy freeplay camera
2024-05-13 20:30:36 -04:00
FlxG . cameras . remove ( funnyCam ) ;
2023-01-22 19:55:30 -05:00
}
2024-04-30 14:36:57 -04:00
function changeDiff ( change : Int = 0 , force : Bool = false ) : Void
2023-01-22 19:55:30 -05:00
{
touchTimer = 0 ;
2024-03-20 14:37:24 -04:00
var currentDifficultyIndex: Int = diffIdsCurrent . indexOf ( currentDifficulty ) ;
2023-01-22 19:55:30 -05:00
2023-10-12 03:20:21 -04:00
if ( currentDifficultyIndex == - 1 ) currentDifficultyIndex = diffIdsCurrent . indexOf ( Constants . DEFAULT_DIFFICULTY ) ;
2023-01-22 19:55:30 -05:00
2023-10-12 03:20:21 -04:00
currentDifficultyIndex += change ;
if ( currentDifficultyIndex < 0 ) currentDifficultyIndex = diffIdsCurrent . length - 1 ;
if ( currentDifficultyIndex >= diffIdsCurrent . length ) currentDifficultyIndex = 0 ;
currentDifficulty = diffIdsCurrent [ currentDifficultyIndex ] ;
2023-10-03 19:14:46 -04:00
2024-04-01 18:34:26 -04:00
var daSong: Null < FreeplaySongData > = grpCapsules . members [ curSelected ] . songData ;
2023-10-10 23:32:01 -04:00
if ( daSong != null )
{
2024-06-20 16:17:53 -04:00
var targetSong: Null < Song > = SongRegistry . instance . fetchEntry ( daSong . songId ) ;
2024-06-11 00:40:43 -04:00
if ( targetSong == null )
{
2024-06-20 16:17:53 -04:00
FlxG . log . warn ( ' W A R N : c o u l d n o t f i n d s o n g w i t h i d ( ${ daSong . songId } ) ' ) ;
2024-06-11 00:40:43 -04:00
return ;
}
2024-06-20 16:17:53 -04:00
var targetVariation: String = targetSong . getFirstValidVariation ( currentDifficulty ) ? ? ' ' ;
2024-06-11 00:40:43 -04:00
// TODO: This line of code makes me sad, but you can't really fix it without a breaking migration.
var suffixedDifficulty = ( targetVariation != Constants . DEFAULT_VARIATION
& & targetVariation != ' e r e c t ' ) ? ' $ currentDifficulty - ${ targetVariation } ' : currentDifficulty ;
2024-06-20 16:17:53 -04:00
var songScore: Null < SaveScoreData > = Save . instance . getSongScore ( daSong . songId , suffixedDifficulty ) ;
2023-10-10 23:32:01 -04:00
intendedScore = songScore ? . score ? ? 0 ;
2024-05-17 20:26:34 -04:00
intendedCompletion = songScore == null ? 0.0 : ( ( songScore . tallies . sick + songScore . tallies . good ) / songScore . tallies . totalNotes ) ;
2023-10-12 03:20:21 -04:00
rememberedDifficulty = currentDifficulty ;
2023-10-10 23:32:01 -04:00
}
e lse
{
intendedScore = 0 ;
intendedCompletion = 0.0 ;
}
2023-01-22 19:55:30 -05:00
2024-01-11 00:30:00 -05:00
if ( intendedCompletion == Math . POSITIVE_INFINITY || intendedCompletion == Math . NEGATIVE_INFINITY || Math . isNaN ( intendedCompletion ) )
{
intendedCompletion = 0 ;
}
2023-10-12 03:20:21 -04:00
grpDifficulties . group . forEach ( function ( diffSprite ) {
diffSprite . visible = false ;
2023-01-22 19:55:30 -05:00
} ) ;
2023-10-12 03:20:21 -04:00
for ( diffSprite in grpDifficulties . group . members )
{
if ( diffSprite == null ) continue ;
if ( diffSprite . difficultyId == currentDifficulty )
{
if ( change != 0 )
{
diffSprite . visible = true ;
diffSprite . offset . y += 5 ;
diffSprite . alpha = 0.5 ;
new FlxTimer ( ) . start ( 1 / 24 , function ( swag ) {
diffSprite . alpha = 1 ;
diffSprite . updateHitbox ( ) ;
} ) ;
}
e lse
{
diffSprite . visible = true ;
}
}
}
2024-01-11 00:30:00 -05:00
2024-04-30 14:36:57 -04:00
if ( change != 0 || force )
2024-01-11 00:30:00 -05:00
{
// Update the song capsules to reflect the new difficulty info.
for ( songCapsule in grpCapsules . members )
{
if ( songCapsule == null ) continue ;
if ( songCapsule . songData != null )
{
songCapsule . songData . currentDifficulty = currentDifficulty ;
songCapsule . init ( null , null , songCapsule . songData ) ;
2024-06-05 18:21:57 -04:00
songCapsule . checkClip ( ) ;
2024-01-11 00:30:00 -05:00
}
e lse
{
songCapsule . init ( null , null , null ) ;
}
}
2024-07-28 01:42:09 -04:00
// Reset the song preview in case we changed variations (normal->erect etc)
playCurSongPreview ( ) ;
2024-01-11 00:30:00 -05:00
}
2024-03-23 18:22:15 -04:00
// Set the album graphic and play the animation if relevant.
2024-06-20 16:17:53 -04:00
var newAlbumId: Null < String > = daSong ? . albumId ;
2024-03-23 18:22:15 -04:00
if ( albumRoll . albumId != newAlbumId )
{
albumRoll . albumId = newAlbumId ;
2024-03-30 00:54:07 -04:00
albumRoll . skipIntro ( ) ;
2024-03-23 18:22:15 -04:00
}
2024-05-11 01:05:51 -04:00
// Set difficulty star count.
albumRoll . setDifficultyStars ( daSong ? . difficultyRating ) ;
2023-01-22 19:55:30 -05:00
}
// Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String)
2024-03-20 14:37:24 -04:00
function clearDaCache ( actualSongTho : String ) : Void
2023-01-22 19:55:30 -05:00
{
for ( song in songs )
{
2023-10-17 00:38:28 -04:00
if ( song == null ) continue ;
2023-01-22 19:55:30 -05:00
if ( song . songName != actualSongTho )
{
trace ( ' t r y i n g t o r e m o v e : ' + song . songName ) ;
// openfl.Assets.cache.clear(Paths.inst(song.songName));
}
}
}
2023-10-16 20:12:40 -04:00
function capsuleOnConfirmRandom ( randomCapsule : SongMenuItem ) : Void
2023-08-06 16:24:34 -04:00
{
2024-03-20 14:37:24 -04:00
trace ( ' R A N D O M S E L E C T E D ' ) ;
2023-08-06 16:24:34 -04:00
2023-10-17 00:38:28 -04:00
busy = true ;
2023-11-07 18:53:50 -05:00
letterSort . inputEnabled = false ;
2023-10-16 20:12:40 -04:00
var availableSongCapsules: Array < SongMenuItem > = grpCapsules . members . filter ( function ( cap : SongMenuItem ) {
// Dead capsules are ones which were removed from the list when changing filters.
return cap . alive && cap . songData != null ;
} ) ;
trace ( ' A v a i l a b l e s o n g s : ${ availableSongCapsules . map ( function ( cap ) {
2024-06-20 16:17:53 -04:00
return cap ? . songData ? . songName ;
2023-10-16 20:12:40 -04:00
} ) } ' ) ;
2023-11-07 18:53:50 -05:00
if ( availableSongCapsules . length == 0 )
{
2024-03-20 14:37:24 -04:00
trace ( ' N o s o n g s a v a i l a b l e ! ' ) ;
2023-11-07 18:53:50 -05:00
busy = false ;
letterSort . inputEnabled = true ;
2024-03-23 17:50:48 -04:00
FunkinSound . playOnce ( Paths . sound ( ' c a n c e l M e n u ' ) ) ;
2023-11-07 18:53:50 -05:00
return ;
}
2023-10-16 20:12:40 -04:00
var targetSong: SongMenuItem = FlxG . random . getObject ( availableSongCapsules ) ;
// Seeing if I can do an animation...
curSelected = grpCapsules . members . indexOf ( targetSong ) ;
changeSelection ( 0 ) ; // Trigger an update.
// Act like we hit Confirm on that song.
capsuleOnConfirmDefault ( targetSong ) ;
2023-10-17 00:38:28 -04:00
}
2023-09-28 20:29:19 -04:00
function capsuleOnConfirmDefault ( cap : SongMenuItem ) : Void
2023-01-22 19:55:30 -05:00
{
2023-10-17 00:38:28 -04:00
busy = true ;
2023-11-07 18:53:50 -05:00
letterSort . inputEnabled = false ;
2023-08-06 16:24:34 -04:00
PlayStatePlaylist . isStoryMode = false ;
2023-01-22 19:55:30 -05:00
2024-06-20 16:17:53 -04:00
var targetSongId: String = cap ? . songData ? . songId ? ? ' u n k n o w n ' ;
var targetSongNullable: Null < Song > = SongRegistry . instance . fetchEntry ( targetSongId ) ;
if ( targetSongNullable == null )
2023-11-28 20:52:45 -05:00
{
2024-06-20 16:17:53 -04:00
FlxG . log . warn ( ' W A R N : c o u l d n o t f i n d s o n g w i t h i d ( ${ targetSongId } ) ' ) ;
2023-11-28 20:52:45 -05:00
return ;
}
2024-06-20 16:17:53 -04:00
var targetSong: Song = targetSongNullable ;
2024-06-06 21:38:00 -04:00
var targetDifficultyId: String = currentDifficulty ;
2024-06-20 16:17:53 -04:00
var targetVariation: Null < String > = targetSong . getFirstValidVariation ( targetDifficultyId , currentCharacter ) ;
var targetLevelId: Null < String > = cap ? . songData ? . levelId ;
PlayStatePlaylist . campaignId = targetLevelId ? ? null ;
2023-08-06 16:24:34 -04:00
2024-06-20 16:17:53 -04:00
var targetDifficulty: Null < SongDifficulty > = targetSong . getDifficulty ( targetDifficultyId , targetVariation ) ;
2024-06-06 21:38:00 -04:00
if ( targetDifficulty == null )
{
FlxG . log . warn ( ' W A R N : c o u l d n o t f i n d d i f f i c u l t y w i t h i d ( ${ targetDifficultyId } ) ' ) ;
return ;
}
2024-06-18 17:56:24 -04:00
var baseInstrumentalId: String = targetDifficulty ? . characters ? . instrumental ? ? ' ' ;
var altInstrumentalIds: Array < String > = targetDifficulty ? . characters ? . altInstrumentals ? ? [ ] ;
var targetInstId: String = baseInstrumentalId ;
// TODO: Make this a UI element.
#if ( debug || FORCE_DEBUG_VERSION )
if ( altInstrumentalIds . length > 0 && FlxG . keys . pressed . CONTROL )
{
targetInstId = altInstrumentalIds [ 0 ] ;
}
#end
2024-06-06 21:38:00 -04:00
2023-08-06 16:24:34 -04:00
// Visual and audio effects.
2024-03-23 17:50:48 -04:00
FunkinSound . playOnce ( Paths . sound ( ' c o n f i r m M e n u ' ) ) ;
2024-06-20 16:17:53 -04:00
if ( dj != null ) dj . confirm ( ) ;
2023-08-06 16:24:34 -04:00
2024-05-31 05:39:53 -04:00
grpCapsules . members [ curSelected ] . forcePosition ( ) ;
2024-06-27 19:50:38 -04:00
grpCapsules . members [ curSelected ] . confirm ( ) ;
2024-05-29 23:34:00 -04:00
// 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 ( " B F b a c k c a r d c o n f i r m r a w " , 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 ;
2023-08-06 16:24:34 -04:00
new FlxTimer ( ) . start ( 1 , function ( tmr : FlxTimer ) {
2024-06-05 15:02:29 -04:00
FunkinSound . emptyPartialQueue ( ) ;
2024-06-20 16:17:53 -04:00
Paths . setCurrentLevel ( cap ? . songData ? . levelId ) ;
2024-02-16 23:48:43 -05:00
LoadingState . loadPlayState (
2023-08-06 16:24:34 -04:00
{
targetSong : targetSong ,
2024-06-06 21:38:00 -04:00
targetDifficulty : targetDifficultyId ,
2024-02-05 21:35:58 -05:00
targetVariation : targetVariation ,
2024-06-06 21:38:00 -04:00
targetInstrumental : targetInstId ,
2024-02-29 18:49:20 -05:00
practiceMode : false ,
minimalMode : false ,
2024-04-01 18:34:26 -04:00
#if ( debug || FORCE_DEBUG_VERSION )
botPlayMode : FlxG . keys . pressed . SHIFT ,
#else
botPlayMode : false ,
#end
2024-03-05 22:27:07 -05:00
// TODO: Make these an option! It's currently only accessible via chart editor.
// startTimestamp: 0.0,
// playbackRate: 0.5,
// botPlayMode: true,
2024-02-16 23:48:43 -05:00
} , true ) ;
2023-08-06 16:24:34 -04:00
} ) ;
}
2023-10-12 03:20:21 -04:00
function rememberSelection ( ) : Void
{
if ( rememberedSongId != null )
{
2024-04-01 18:34:26 -04:00
curSelected = currentFilteredSongs . findIndex ( function ( song ) {
2023-10-12 03:20:21 -04:00
if ( song == null ) return false ;
return song . songId == rememberedSongId ;
} ) ;
2024-04-01 18:34:26 -04:00
if ( curSelected == - 1 ) curSelected = 0 ;
2023-10-12 03:20:21 -04:00
}
if ( rememberedDifficulty != null )
{
currentDifficulty = rememberedDifficulty ;
}
}
2024-03-11 23:42:32 -04:00
function changeSelection ( change : Int = 0 ) : Void
2023-01-22 19:55:30 -05:00
{
2024-03-20 14:37:24 -04:00
var prevSelected: Int = curSelected ;
2023-10-16 20:12:40 -04:00
2023-01-22 19:55:30 -05:00
curSelected += change ;
2024-06-10 12:04:18 -04:00
if ( ! prepForNewRank && curSelected != prevSelected ) FunkinSound . playOnce ( Paths . sound ( ' s c r o l l M e n u ' ) , 0.4 ) ;
2023-08-09 03:03:58 -04:00
if ( curSelected < 0 ) curSelected = grpCapsules . countLiving ( ) - 1 ;
if ( curSelected >= grpCapsules . countLiving ( ) ) curSelected = 0 ;
2023-01-22 19:55:30 -05:00
2024-03-20 14:37:24 -04:00
var daSongCapsule: SongMenuItem = grpCapsules . members [ curSelected ] ;
2023-10-16 20:12:40 -04:00
if ( daSongCapsule . songData != null )
2023-08-09 03:03:58 -04:00
{
2024-06-20 16:17:53 -04:00
var songScore: Null < SaveScoreData > = Save . instance . getSongScore ( daSongCapsule . songData . songId , currentDifficulty ) ;
2023-10-10 23:32:01 -04:00
intendedScore = songScore ? . score ? ? 0 ;
2024-05-17 20:26:34 -04:00
intendedCompletion = songScore == null ? 0.0 : ( ( songScore . tallies . sick + songScore . tallies . good ) / songScore . tallies . totalNotes ) ;
2023-11-01 23:20:47 -04:00
diffIdsCurrent = daSongCapsule . songData . songDifficulties ;
rememberedSongId = daSongCapsule . songData . songId ;
2023-10-12 03:20:21 -04:00
changeDiff ( ) ;
2023-08-09 03:03:58 -04:00
}
e lse
{
intendedScore = 0 ;
2023-10-10 23:32:01 -04:00
intendedCompletion = 0.0 ;
2024-04-01 18:34:26 -04:00
diffIdsCurrent = diffIdsTotal ;
2023-10-12 03:20:21 -04:00
rememberedSongId = null ;
rememberedDifficulty = null ;
2024-03-28 01:46:50 -04:00
albumRoll . albumId = null ;
2023-08-09 03:03:58 -04:00
}
2023-01-22 19:55:30 -05:00
for ( index => capsule in grpCapsules . members )
{
2023-08-04 15:59:17 -04:00
index += 1 ;
2023-01-22 19:55:30 -05:00
2023-09-19 23:27:07 -04:00
capsule . selected = index == curSelected + 1 ;
2023-01-22 19:55:30 -05:00
2023-08-04 17:10:27 -04:00
capsule . targetPos . y = capsule . intendedY ( index - curSelected ) ;
2023-01-22 19:55:30 -05:00
capsule . targetPos . x = 270 + ( 60 * ( Math . sin ( index - curSelected ) ) ) ;
2023-01-22 22:25:45 -05:00
if ( index < curSelected ) capsule . targetPos . y -= 100 ; // another 100 for good measure
2023-01-22 19:55:30 -05:00
}
2024-06-05 20:49:33 -04:00
if ( grpCapsules . countLiving ( ) > 0 && ! prepForNewRank )
2023-08-13 22:12:08 -04:00
{
2024-06-05 20:49:33 -04:00
playCurSongPreview ( daSongCapsule ) ;
2023-08-13 22:12:08 -04:00
grpCapsules . members [ curSelected ] . selected = true ;
}
2023-01-22 19:55:30 -05:00
}
2024-03-28 22:33:50 -04:00
2024-07-28 01:42:09 -04:00
public function playCurSongPreview ( ? daSongCapsule : SongMenuItem ) : Void
2024-06-05 20:49:33 -04:00
{
2024-07-28 01:42:09 -04:00
if ( daSongCapsule == null ) daSongCapsule = grpCapsules . members [ curSelected ] ;
2024-06-05 20:49:33 -04:00
if ( curSelected == 0 )
{
FunkinSound . playMusic ( ' f r e e p l a y R a n d o m ' ,
{
startingVolume : 0.0 ,
overrideExisting : true ,
restartTrack : false
} ) ;
FlxG . sound . music . fadeIn ( 2 , 0 , 0.8 ) ;
}
e lse
{
2024-06-20 16:17:53 -04:00
var previewSongId: Null < String > = daSongCapsule ? . songData ? . songId ;
if ( previewSongId == null ) return ;
var previewSong: Null < Song > = SongRegistry . instance . fetchEntry ( previewSongId ) ;
2024-06-18 17:56:24 -04:00
var songDifficulty = previewSong ? . getDifficulty ( currentDifficulty ,
previewSong ? . getVariationsByCharacter ( currentCharacter ) ? ? Constants . DEFAULT_VARIATION_LIST ) ;
var baseInstrumentalId: String = songDifficulty ? . characters ? . instrumental ? ? ' ' ;
var altInstrumentalIds: Array < String > = songDifficulty ? . characters ? . altInstrumentals ? ? [ ] ;
var instSuffix: String = baseInstrumentalId ;
// TODO: Make this a UI element.
#if ( debug || FORCE_DEBUG_VERSION )
if ( altInstrumentalIds . length > 0 && FlxG . keys . pressed . CONTROL )
{
instSuffix = altInstrumentalIds [ 0 ] ;
}
#end
2024-06-10 12:42:27 -04:00
instSuffix = ( instSuffix != ' ' ) ? ' - $ instSuffix ' : ' ' ;
2024-06-18 17:56:24 -04:00
2024-06-20 16:17:53 -04:00
trace ( ' A t t e m p t i n g t o p l a y p a r t i a l p r e v i e w : ${ previewSongId } : ${ instSuffix } ' ) ;
FunkinSound . playMusic ( previewSongId ,
2024-06-05 20:49:33 -04:00
{
startingVolume : 0.0 ,
overrideExisting : true ,
restartTrack : false ,
2024-06-17 12:22:49 -04:00
mapTimeChanges : false , // The music metadata is not alongside the audio file so this won't work.
2024-06-05 20:49:33 -04:00
pathsFunction : INST ,
2024-06-10 12:42:27 -04:00
suffix : instSuffix ,
2024-06-05 20:49:33 -04:00
partialParams :
{
loadPartial : true ,
start : 0.05 ,
end : 0.25
} ,
onLoad : function ( ) {
FlxG . sound . music . fadeIn ( 2 , 0 , 0.4 ) ;
}
} ) ;
}
}
2024-03-28 22:33:50 -04:00
/ * *
* Build an instance of ` FreeplayState ` that is above the ` MainMenuState ` .
* @ return The MainMenuState with the FreeplayState as a substate .
* /
public static function build ( ? params : FreeplayStateParams , ? stickers : StickerSubState ) : MusicBeatState
{
2024-05-31 05:39:53 -04:00
var result: MainMenuState ;
2024-06-20 16:17:53 -04:00
if ( params ? . fromResults ? . playRankAnim ? ? false ) r e s u l t = n e w M a i n M e n u S t a t e ( t r u e ) ;
2024-06-01 19:25:52 -04:00
e lse
2024-05-31 05:39:53 -04:00
result = new MainMenuState ( false ) ;
2024-03-28 22:33:50 -04:00
result . openSubState ( new FreeplayState ( params , stickers ) ) ;
2024-05-01 15:22:20 -04:00
result . persistentUpdate = false ;
result . persistentDraw = true ;
2024-03-28 22:33:50 -04:00
return result ;
}
2021-12-07 19:29:26 -05:00
}
2024-03-20 14:37:24 -04:00
/ * *
* The difficulty selector arrows to the left and right of the difficulty .
* /
2021-12-07 19:29:26 -05:00
class DifficultySelector extends FlxSprite
{
2023-01-22 19:55:30 -05:00
var controls: Controls ;
var whiteShader: PureColor ;
2021-12-07 19:29:26 -05:00
2023-01-22 19:55:30 -05:00
public function n e w ( x : Float , y : Float , flipped : Bool , controls : Controls )
{
super ( x , y ) ;
2021-12-07 19:29:26 -05:00
2023-01-22 19:55:30 -05:00
this . controls = controls ;
2021-12-07 19:29:26 -05:00
2023-01-22 19:55:30 -05:00
frames = Paths . getSparrowAtlas ( ' f r e e p l a y / f r e e p l a y S e l e c t o r ' ) ;
2024-03-20 14:37:24 -04:00
animation . addByPrefix ( ' s h i n e ' , ' a r r o w p o i n t e r l o o p ' , 24 ) ;
2023-01-22 19:55:30 -05:00
animation . play ( ' s h i n e ' ) ;
2021-12-07 19:29:26 -05:00
2023-01-22 19:55:30 -05:00
whiteShader = new PureColor ( FlxColor . WHITE ) ;
2021-12-07 22:34:01 -05:00
2023-01-22 19:55:30 -05:00
shader = whiteShader ;
2021-12-07 22:34:01 -05:00
2023-01-22 19:55:30 -05:00
flipX = flipped ;
}
2021-04-08 17:29:31 -04:00
2024-03-11 23:42:32 -04:00
override function update ( elapsed : Float ) : Void
2023-01-22 19:55:30 -05:00
{
2024-06-18 17:56:24 -04:00
if ( flipX && controls . UI_RIGHT_P ) moveShitDown ( ) ;
if ( ! flipX && controls . UI_LEFT_P ) moveShitDown ( ) ;
2021-12-07 19:29:26 -05:00
2023-01-22 19:55:30 -05:00
super . update ( elapsed ) ;
}
2021-12-07 19:29:26 -05:00
2024-03-11 23:42:32 -04:00
function moveShitDown ( ) : Void
2023-01-22 19:55:30 -05:00
{
offset . y -= 5 ;
2021-04-08 17:29:31 -04:00
2023-01-22 19:55:30 -05:00
whiteShader . colorSet = true ;
2021-12-07 22:34:01 -05:00
2023-08-06 22:20:18 -04:00
scale . x = scale . y = 0.5 ;
2023-03-15 21:05:15 -04:00
new FlxTimer ( ) . start ( 2 / 24 , function ( tmr ) {
2023-08-06 22:20:18 -04:00
scale . x = scale . y = 1 ;
2023-01-22 19:55:30 -05:00
whiteShader . colorSet = false ;
updateHitbox ( ) ;
} ) ;
}
2020-10-21 14:05:27 -04:00
}
2021-02-24 20:52:59 -05:00
2024-03-20 14:37:24 -04:00
/ * *
* Structure for t h e c u r r e n t s o n g f i l t e r .
* /
2022-09-28 02:50:53 -04:00
typedef SongFilter =
{
2023-01-22 19:55:30 -05:00
var filterType: FilterType ;
var ? filterData: Dynamic ;
2022-09-28 02:50:53 -04:00
}
2024-03-20 14:37:24 -04:00
/ * *
* Possible types to use for t h e s o n g f i l t e r .
* /
2022-09-28 02:50:53 -04:00
enum a b s t r a c t FilterType ( S t r i n g )
{
2024-03-20 14:37:24 -04:00
/ * *
* Filter to songs which start with a string
* /
public var STARTSWITH;
/ * *
* Filter to songs which match a regular expression
* /
public var REGEXP;
/ * *
* Filter to songs which are favorited
* /
public var FAVORITE;
/ * *
* Filter to all songs
* /
public var ALL;
2022-09-28 02:50:53 -04:00
}
2024-03-20 14:37:24 -04:00
/ * *
* Data about a specific song in the freeplay menu .
* /
2023-06-09 18:25:21 -04:00
class FreeplaySongData
2021-02-24 20:52:59 -05:00
{
2024-03-20 14:37:24 -04:00
/ * *
* Whether or not the song has been favorited .
* /
2023-10-12 03:20:21 -04:00
public var isFav: Bool = false ;
2024-06-05 20:49:33 -04:00
public var isNew: Bool = false ;
2024-01-11 00:30:00 -05:00
var song: Song ;
2024-03-20 14:37:24 -04:00
public var levelId( default , null ) : String = ' ' ;
public var songId( default , null ) : String = ' ' ;
2024-01-11 00:30:00 -05:00
public var songDifficulties( default , null ) : Array < String > = [ ] ;
2023-01-22 19:55:30 -05:00
2024-03-20 14:37:24 -04:00
public var songName( default , null ) : String = ' ' ;
public var songCharacter( default , null ) : String = ' ' ;
2024-05-29 23:34:00 -04:00
public var songStartingBpm( default , null ) : Float = 0 ;
2024-05-11 01:05:51 -04:00
public var difficultyRating( default , null ) : Int = 0 ;
2024-03-28 01:46:50 -04:00
public var albumId( default , null ) : Null < String > = null ;
2024-01-11 00:30:00 -05:00
public var currentDifficulty( default , set ) : String = Constants . DEFAULT_DIFFICULTY ;
2024-05-11 01:05:51 -04:00
2024-05-30 05:25:51 -04:00
public var scoringRank: Null < ScoringRank > = null ;
2024-05-11 01:05:51 -04:00
var displayedVariations: Array < String > = [ Constants . DEFAULT_VARIATION ] ;
2024-01-11 00:30:00 -05:00
function set_currentDifficulty ( value : String ) : String
{
2024-06-08 18:29:55 -04:00
if ( currentDifficulty == value ) return value ;
2024-01-11 00:30:00 -05:00
currentDifficulty = value ;
2024-02-05 21:35:58 -05:00
updateValues ( displayedVariations ) ;
2024-01-11 00:30:00 -05:00
return value ;
}
2024-02-05 21:35:58 -05:00
public function n e w ( levelId : String , songId : String , song : Song , ? displayedVariations : Array < String > )
2023-01-22 19:55:30 -05:00
{
2023-06-09 18:25:21 -04:00
this . levelId = levelId ;
2024-01-11 00:30:00 -05:00
this . songId = songId ;
this . song = song ;
2024-05-21 02:49:07 -04:00
this . isFav = Save . instance . isSongFavorited ( songId ) ;
2024-02-05 21:35:58 -05:00
if ( displayedVariations != null ) this . displayedVariations = displayedVariations ;
2024-01-11 00:30:00 -05:00
2024-02-05 21:35:58 -05:00
updateValues ( displayedVariations ) ;
2024-01-11 00:30:00 -05:00
}
2024-05-21 02:49:07 -04:00
/ * *
* 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 ) ;
}
e lse
{
Save . instance . unfavoriteSong ( this . songId ) ;
}
return isFav ;
}
2024-03-20 14:37:24 -04:00
function updateValues ( variations : Array < String > ) : Void
2024-01-11 00:30:00 -05:00
{
2024-07-28 01:42:09 -04:00
this . songDifficulties = song . listSuffixedDifficulties ( variations , false , false ) ;
2024-01-11 00:30:00 -05:00
if ( ! this . songDifficulties . contains ( currentDifficulty ) ) currentDifficulty = Constants . DEFAULT_DIFFICULTY ;
2024-06-07 14:24:57 -04:00
var songDifficulty: SongDifficulty = song . getDifficulty ( currentDifficulty , null , variations ) ;
2024-01-11 00:30:00 -05:00
if ( songDifficulty == null ) return ;
2024-05-29 23:34:00 -04:00
this . songStartingBpm = songDifficulty . getStartingBPM ( ) ;
2024-01-11 00:30:00 -05:00
this . songName = songDifficulty . songName ;
this . songCharacter = songDifficulty . characters . opponent ;
2024-05-11 01:05:51 -04:00
this . difficultyRating = songDifficulty . difficultyRating ;
2024-03-28 01:46:50 -04:00
if ( songDifficulty . album == null )
{
FlxG . log . warn ( ' N o a l b u m f o r : ${ songDifficulty . songName } ' ) ;
this . albumId = Constants . DEFAULT_ALBUM_ID ;
}
e lse
{
this . albumId = songDifficulty . album ;
}
2024-05-30 05:25:51 -04:00
2024-06-14 09:53:33 -04:00
// TODO: This line of code makes me sad, but you can't really fix it without a breaking migration.
// `easy`, `erect`, `normal-pico`, etc.
var suffixedDifficulty = ( songDifficulty . variation != Constants . DEFAULT_VARIATION
& & songDifficulty . variation != ' e r e c t ' ) ? ' $ currentDifficulty - ${ songDifficulty . variation } ' : currentDifficulty ;
2024-05-30 05:25:51 -04:00
2024-06-14 09:53:33 -04:00
this . scoringRank = Save . instance . getSongRank ( songId , suffixedDifficulty ) ;
2024-06-05 20:49:33 -04:00
this . isNew = song . isSongNew ( currentDifficulty ) ;
2023-01-22 19:55:30 -05:00
}
2021-02-24 20:52:59 -05:00
}
2023-03-15 21:05:15 -04:00
2024-03-20 14:37:24 -04:00
/ * *
* The map storing information about the exit movers .
* /
typedef ExitMoverData = Map < Array < FlxSprite > , MoveData > ;
/ * *
* The data for a n e x i t m o v e r .
* /
2023-03-15 21:05:15 -04:00
typedef MoveData =
{
2023-03-16 00:17:52 -04:00
var ? x: Float ;
var ? y: Float ;
var ? speed: Float ;
var ? wait: Float ;
2023-03-15 21:05:15 -04:00
}
2023-10-12 03:20:21 -04:00
2024-03-20 14:37:24 -04:00
/ * *
* The sprite for t h e d i f f i c u l t y
* /
2023-10-12 03:20:21 -04:00
class DifficultySprite extends FlxSprite
{
2024-03-20 14:37:24 -04:00
/ * *
* The difficulty id which this sprite represents .
* /
2023-10-12 03:20:21 -04:00
public var difficultyId: String ;
public function n e w ( diffId : String )
{
super ( ) ;
difficultyId = diffId ;
2024-07-28 01:42:09 -04:00
var assetDiffId: String = diffId ;
while ( ! Assets . exists ( Paths . image ( ' f r e e p l a y / f r e e p l a y ${ assetDiffId } ' ) ) )
{
// Remove the last suffix of the difficulty id until we find an asset or there are no more suffixes.
var assetDiffIdParts: Array < String > = assetDiffId . split ( ' - ' ) ;
assetDiffIdParts . pop ( ) ;
if ( assetDiffIdParts . length == 0 ) break ;
assetDiffId = assetDiffIdParts . join ( ' - ' ) ;
}
// Check for an XML to use an animation instead of an image.
if ( Assets . exists ( Paths . file ( ' i m a g e s / f r e e p l a y / f r e e p l a y ${ assetDiffId } . x m l ' ) ) )
2023-11-20 11:12:50 -05:00
{
2024-07-28 01:42:09 -04:00
this . frames = Paths . getSparrowAtlas ( ' f r e e p l a y / f r e e p l a y ${ assetDiffId } ' ) ;
2023-11-20 11:12:50 -05:00
this . animation . addByPrefix ( ' i d l e ' , ' i d l e 0 ' , 24 , true ) ;
if ( Preferences . flashingLights ) this . animation . play ( ' i d l e ' ) ;
}
e lse
{
2024-07-28 01:42:09 -04:00
this . loadGraphic ( Paths . image ( ' f r e e p l a y / f r e e p l a y ' + assetDiffId ) ) ;
2023-11-20 11:12:50 -05:00
}
2023-10-12 03:20:21 -04:00
}
}