2023-11-07 09:04:22 +00:00
package funkin . ui . freeplay ;
2021-04-08 00:19:49 +00:00
2024-08-23 12:36:35 +00:00
import funkin . ui . freeplay . backcards . BackingCard ;
import funkin . ui . freeplay . backcards . BoyfriendCard ;
import funkin . ui . freeplay . backcards . PicoCard ;
2023-10-11 03:32:01 +00:00
import flixel . addons . transition . FlxTransitionableState ;
import flixel . addons . ui . FlxInputText ;
2021-08-22 00:45:03 +00:00
import flixel . FlxCamera ;
2020-10-21 18:05:27 +00:00
import flixel . FlxSprite ;
2021-10-22 03:08:48 +00:00
import flixel . group . FlxGroup ;
2023-10-11 03:32:01 +00:00
import flixel . group . FlxGroup . FlxTypedGroup ;
2024-03-12 03:42:32 +00:00
import flixel . group . FlxSpriteGroup . FlxTypedSpriteGroup ;
2021-08-21 23:53:08 +00:00
import flixel . input . touch . FlxTouch ;
2021-08-24 19:28:04 +00:00
import flixel . math . FlxAngle ;
import flixel . math . FlxPoint ;
2023-10-11 03:32:01 +00:00
import flixel . system . debug . watch . Tracker . TrackerProfile ;
2020-10-21 18:05:27 +00:00
import flixel . text . FlxText ;
2021-10-22 03:08:48 +00:00
import flixel . tweens . FlxEase ;
2021-03-02 05:46:28 +00:00
import flixel . tweens . FlxTween ;
2024-06-20 20:17:53 +00:00
import flixel . tweens . misc . ShakeTween ;
2020-11-07 02:17:27 +00:00
import flixel . util . FlxColor ;
2021-10-22 03:08:48 +00:00
import flixel . util . FlxSpriteUtil ;
2021-10-21 21:40:53 +00:00
import flixel . util . FlxTimer ;
2024-03-12 03:42:32 +00:00
import funkin . audio . FunkinSound ;
2024-06-18 21:56:24 +00:00
import funkin . data . freeplay . player . PlayerRegistry ;
2023-10-11 03:32:01 +00:00
import funkin . data . song . SongRegistry ;
2024-06-20 20:17:53 +00:00
import funkin . data . story . level . LevelRegistry ;
import funkin . effects . IntervalShake ;
import funkin . graphics . adobeanimate . FlxAtlasSprite ;
2024-03-12 03:42:32 +00:00
import funkin . graphics . FunkinCamera ;
import funkin . graphics . FunkinSprite ;
2023-11-07 09:04:22 +00:00
import funkin . graphics . shaders . AngleMask ;
2024-06-20 20:17:53 +00:00
import funkin . graphics . shaders . GaussianBlurShader ;
2023-11-07 09:04:22 +00:00
import funkin . graphics . shaders . HSVShader ;
import funkin . graphics . shaders . PureColor ;
2024-08-23 12:36:35 +00:00
import funkin . graphics . shaders . BlueFade ;
2023-11-07 09:04:22 +00:00
import funkin . graphics . shaders . StrokeShader ;
2024-08-23 12:36:35 +00:00
import openfl . filters . ShaderFilter ;
2024-01-11 05:30:00 +00:00
import funkin . input . Controls ;
2023-10-11 03:32:01 +00:00
import funkin . play . PlayStatePlaylist ;
2024-06-20 20:17:53 +00:00
import funkin . play . scoring . Scoring ;
import funkin . play . scoring . Scoring . ScoringRank ;
2023-10-11 03:32:01 +00:00
import funkin . play . song . Song ;
import funkin . save . Save ;
import funkin . save . Save . SaveScoreData ;
2024-01-11 05:30:00 +00:00
import funkin . ui . AtlasText ;
2024-06-20 20:17:53 +00:00
import funkin . ui . freeplay . charselect . PlayableCharacter ;
import funkin . ui . freeplay . SongMenuItem . FreeplayRank ;
2024-01-11 05:30:00 +00:00
import funkin . ui . mainmenu . MainMenuState ;
2023-11-07 09:04:22 +00:00
import funkin . ui . MusicBeatSubState ;
2024-06-20 20:17:53 +00:00
import funkin . ui . story . Level ;
2023-11-07 09:04:22 +00:00
import funkin . ui . transition . LoadingState ;
import funkin . ui . transition . StickerSubState ;
import funkin . util . MathUtil ;
2024-06-20 20:17:53 +00:00
import funkin . util . SortUtil ;
2022-03-24 03:27:48 +00:00
import lime . utils . Assets ;
2024-06-20 20:17:53 +00:00
import openfl . display . BlendMode ;
2020-10-21 18:05:27 +00:00
2024-02-05 18:35:30 +00:00
/ * *
* Parameters used to initialize the FreeplayState .
* /
typedef FreeplayStateParams =
{
2024-02-06 02:35:58 +00:00
? character : String ,
2024-05-30 09:25:51 +00: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 23:25:52 +00:00
/ * *
* Whether or not to play the rank animation on returning to freeplay .
* /
var playRankAnim: Bool ;
2024-05-30 09:25:51 +00: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 18:35:30 +00:00
} ;
2024-03-20 18:37:24 +00: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 20:17:53 +00:00
@ : nullSafety
2023-06-01 22:52:58 +00:00
class FreeplayState extends MusicBeatSubState
2020-10-21 18:05:27 +00:00
{
2024-02-10 04:13:40 +00: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 21:56:24 +00:00
final currentCharacterId : String ;
final currentCharacter : PlayableCharacter ;
2024-02-06 02:35:58 +00:00
2024-02-09 19:58:57 +00: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 21:16:26 +00:00
*
2024-02-09 19:58:57 +00: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 07:20:21 +00:00
var songs: Array < Null < FreeplaySongData > > = [ ] ;
var diffIdsCurrent: Array < String > = [ ] ;
var diffIdsTotal: Array < String > = [ ] ;
2020-10-21 18:05:27 +00:00
2023-01-23 00:55:30 +00:00
var curSelected: Int = 0 ;
2023-10-12 07:20:21 +00:00
var currentDifficulty: String = Constants . DEFAULT_DIFFICULTY ;
2020-11-07 02:17:27 +00:00
2023-01-23 00:55:30 +00:00
var fp: FreeplayScore ;
2024-01-11 05:30:00 +00:00
var txtCompletion: AtlasText ;
2023-01-23 00:55:30 +00:00
var lerpCompletion: Float = 0 ;
var intendedCompletion: Float = 0 ;
var lerpScore: Float = 0 ;
var intendedScore: Int = 0 ;
2020-10-21 18:05:27 +00:00
2023-10-12 07:20:21 +00:00
var grpDifficulties: FlxTypedSpriteGroup < DifficultySprite > ;
2021-12-07 22:41:18 +00:00
2023-01-23 00:55:30 +00:00
var coolColors: Array < Int > = [
2024-03-20 18:37:24 +00:00
0xFF9271FD ,
0xFF9271FD ,
0xFF223344 ,
2023-01-23 00:55:30 +00:00
0xFF941653 ,
2024-03-20 18:37:24 +00:00
0xFFFC96D7 ,
0xFFA0D1FF ,
0xFFFF78BF ,
0xFFF6B604
2023-01-23 00:55:30 +00:00
] ;
2021-03-02 05:46:28 +00:00
2023-01-23 03:25:45 +00:00
var grpSongs: FlxTypedGroup < Alphabet > ;
var grpCapsules: FlxTypedGroup < SongMenuItem > ;
var curPlaying: Bool = false ;
2020-11-01 19:16:22 +00:00
2024-06-20 20:17:53 +00:00
var dj: Null < FreeplayDJ > = null ;
2022-11-15 07:23:44 +00:00
2024-03-20 18:37:24 +00:00
var ostName: FlxText ;
var albumRoll: AlbumRoll ;
2023-11-07 23:53:50 +00:00
var letterSort: LetterSort ;
2024-03-20 18:37:24 +00:00
var exitMovers: ExitMoverData = new Map ( ) ;
2022-09-26 22:22:45 +00:00
2024-08-23 12:36:35 +00:00
var exitMoversCharSel: ExitMoverData = new Map ( ) ;
2024-06-20 20:17:53 +00:00
var stickerSubState: Null < StickerSubState > = null ;
2023-04-06 05:39:27 +00:00
2024-04-02 01:59:53 +00:00
public static var rememberedDifficulty: Null < String > = Constants . DEFAULT_DIFFICULTY ;
2024-04-03 05:40:08 +00:00
public static var rememberedSongId: Null < String > = ' t u t o r i a l ' ;
2023-10-12 07:20:21 +00:00
2024-05-30 03:34:00 +00:00
var funnyCam: FunkinCamera ;
var rankCamera: FunkinCamera ;
var rankBg: FunkinSprite ;
var rankVignette: FlxSprite ;
2024-08-23 12:36:35 +00:00
var backingCard: Null < BackingCard > = null ;
2024-05-30 03:34:00 +00:00
2024-08-23 12:36:35 +00:00
public var bgDad: FlxSprite ;
2024-05-30 03:34:00 +00:00
2024-05-30 09:25:51 +00:00
var fromResultsParams: Null < FromResultsParams > = null ;
2024-05-31 09:39:53 +00:00
var prepForNewRank: Bool = false ;
2024-02-06 02:35:58 +00:00
public function n e w ( ? params : FreeplayStateParams , ? stickers : StickerSubState )
2023-04-06 05:39:27 +00:00
{
2024-06-18 21:56:24 +00:00
currentCharacterId = params ? . character ? ? Constants . DEFAULT_CHARACTER ;
2024-06-20 20:17:53 +00: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 18:35:30 +00:00
2024-05-30 09:25:51 +00:00
fromResultsParams = params ? . fromResults ;
2024-06-01 23:25:52 +00:00
if ( fromResultsParams ? . playRankAnim == true )
{
2024-05-31 09:39:53 +00:00
prepForNewRank = true ;
}
2024-06-20 20:17:53 +00:00
super ( FlxColor . TRANSPARENT ) ;
2024-06-20 05:24:36 +00:00
if ( stickers ? . members != null )
2023-04-06 05:39:27 +00:00
{
stickerSubState = stickers ;
}
2024-08-23 12:36:35 +00:00
switch ( currentCharacterId )
{
c ase ' b f ' :
backingCard = new BoyfriendCard ( currentCharacter ) ;
c ase ' p i c o ' :
backingCard = new PicoCard ( currentCharacter ) ;
d efault :
backingCard = new BackingCard ( currentCharacter ) ;
}
2024-06-20 20:17:53 +00: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 ) ;
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 ) ;
grpCapsules = new FlxTypedGroup < SongMenuItem > ( ) ;
grpDifficulties = new FlxTypedSpriteGroup < DifficultySprite > ( - 300 , 80 ) ;
letterSort = new LetterSort ( 400 , 75 ) ;
grpSongs = new FlxTypedGroup < Alphabet > ( ) ;
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 ) ;
ostName = new FlxText ( 8 , 8 , FlxG . width - 8 - 8 , ' O F F I C I A L O S T ' , 48 ) ;
2024-08-23 12:36:35 +00:00
bgDad = new FlxSprite ( backingCard . 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 ' ) ) ;
2023-04-06 05:39:27 +00:00
}
2024-08-23 12:36:35 +00:00
var fadeShader: BlueFade = new BlueFade ( ) ;
2023-04-06 05:39:27 +00:00
override function create ( ) : Void
2023-01-23 00:55:30 +00:00
{
2023-04-06 05:39:27 +00:00
super . create ( ) ;
2024-05-03 03:02:47 +00:00
FlxG . state . persistentUpdate = false ;
2023-01-23 00:55:30 +00:00
FlxTransitionableState . skipNextTransIn = true ;
2021-10-22 03:08:48 +00:00
2024-08-23 12:36:35 +00:00
var fadeShaderFilter: ShaderFilter = new ShaderFilter ( fadeShader ) ;
funnyCam . setFilters ( [ fadeShaderFilter ] ) ;
2023-04-06 05:39:27 +00:00
if ( stickerSubState != null )
{
this . persistentUpdate = true ;
this . persistentDraw = true ;
openSubState ( stickerSubState ) ;
stickerSubState . degenStickers ( ) ;
}
2023-01-23 00:55:30 +00:00
#if discord_rpc
// Updating Discord Rich Presence
2024-03-16 04:55:57 +00:00
DiscordClient . changePresence ( ' I n t h e M e n u s ' , null ) ;
2023-01-23 00:55:30 +00:00
#end
2021-05-06 10:54:57 +00:00
2023-01-23 00:55:30 +00:00
var isDebug: Bool = false ;
2021-05-06 10:54:57 +00:00
2023-01-23 00:55:30 +00:00
#if debug
isDebug = true ;
#end
2021-05-06 10:54:57 +00:00
2024-05-31 09:39:53 +00:00
if ( prepForNewRank == false )
{
FunkinSound . playMusic ( ' f r e a k y M e n u ' ,
2024-06-01 23:25:52 +00:00
{
overrideExisting : true ,
restartTrack : false
} ) ;
2024-05-31 09:39:53 +00:00
}
2020-11-01 19:16:22 +00:00
2023-10-11 03:32:01 +00:00
// Add a null entry that represents the RANDOM option
songs . push ( null ) ;
2021-03-01 23:59:51 +00:00
2023-09-29 00:29:19 +00:00
// programmatically adds the songs via LevelRegistry and SongRegistry
2024-05-02 01:51:33 +00:00
for ( levelId in LevelRegistry . instance . listSortedLevelIds ( ) )
2023-09-29 00:29:19 +00:00
{
2024-06-20 20:17:53 +00:00
var level: Null < Level > = LevelRegistry . instance . fetchEntry ( levelId ) ;
2024-05-11 18:11:51 +00: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-29 00:29:19 +00:00
{
2024-06-20 20:17:53 +00:00
var song: Null < Song > = SongRegistry . instance . fetchEntry ( songId ) ;
2023-10-12 07:20:21 +00:00
2024-05-11 18:11:51 +00: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 05:05:51 +00:00
// Only display songs which actually have available difficulties for the current character.
2024-06-18 21:56:24 +00: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 05:42:09 +00:00
var availableDifficultiesForSong: Array < String > = song . listSuffixedDifficulties ( displayedVariations , false , false ) ;
2024-06-18 21:56:24 +00: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-06 02:35:58 +00:00
if ( availableDifficultiesForSong . length == 0 ) continue ;
2023-10-12 07:20:21 +00:00
2024-02-06 02:35:58 +00:00
songs . push ( new FreeplaySongData ( levelId , songId , song , displayedVariations ) ) ;
for ( difficulty in availableDifficultiesForSong )
2023-10-12 07:20:21 +00:00
{
diffIdsTotal . pushUnique ( difficulty ) ;
}
2023-09-29 00:29:19 +00:00
}
}
2021-09-06 18:50:04 +00:00
2023-01-23 00:55:30 +00:00
// LOAD MUSIC
2020-10-21 18:05:27 +00:00
2023-01-23 00:55:30 +00:00
// LOAD CHARACTERS
2020-10-21 18:05:27 +00:00
2023-01-23 00:55:30 +00:00
trace ( FlxG . width ) ;
trace ( FlxG . camera . zoom ) ;
trace ( FlxG . camera . initialZoom ) ;
trace ( FlxCamera . defaultZoom ) ;
2020-10-25 20:51:06 +00:00
2024-08-23 12:36:35 +00:00
if ( backingCard != null )
{
add ( backingCard ) ;
backingCard . init ( ) ;
backingCard . applyExitMovers ( exitMovers , exitMoversCharSel ) ;
}
2024-05-30 03:34:00 +00:00
2024-06-19 00:07:27 +00:00
if ( currentCharacter ? . getFreeplayDJData ( ) != null )
{
dj = new FreeplayDJ ( 640 , 366 , currentCharacterId ) ;
exitMovers . set ( [ dj ] ,
{
x : - dj . width * 1.6 ,
speed : 0.5
} ) ;
add ( dj ) ;
2024-08-23 12:36:35 +00:00
exitMoversCharSel . set ( [ dj ] ,
{
y : - 175 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2024-06-19 00:07:27 +00:00
}
2023-01-23 00:55:30 +00: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 19:57:45 +00: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 04:17:52 +00:00
exitMovers . set ( [ blackOverlayBullshitLOLXD , bgDad ] ,
2023-03-16 01:05:15 +00:00
{
x : FlxG . width * 1.5 ,
2023-03-16 04:17:52 +00:00
speed : 0.4 ,
2023-03-16 01:05:15 +00:00
wait : 0
} ) ;
2024-08-23 12:36:35 +00:00
exitMoversCharSel . set ( [ blackOverlayBullshitLOLXD , bgDad ] ,
{
y : - 100 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2023-01-23 00:55:30 +00:00
add ( bgDad ) ;
2024-08-23 12:36:35 +00:00
// backingCard.pinkBack.width * 0.74
FlxTween . tween ( blackOverlayBullshitLOLXD , { x : 387.76 } , 0.7 , { ease : FlxEase . quintOut } ) ;
2023-01-23 00:55:30 +00:00
blackOverlayBullshitLOLXD . shader = bgDad . shader ;
2024-05-30 03:34:00 +00:00
rankBg . makeSolidColor ( FlxG . width , FlxG . height , 0xD3000000 ) ;
add ( rankBg ) ;
2023-01-23 00:55:30 +00:00
add ( grpSongs ) ;
add ( grpCapsules ) ;
add ( grpDifficulties ) ;
2023-03-16 04:17:52 +00:00
exitMovers . set ( [ grpDifficulties ] ,
{
x : - 300 ,
speed : 0.25 ,
wait : 0
} ) ;
2024-08-23 12:36:35 +00:00
exitMoversCharSel . set ( [ grpDifficulties ] ,
{
y : - 270 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2023-10-12 07:20:21 +00:00
for ( diffId in diffIdsTotal )
{
var diffSprite: DifficultySprite = new DifficultySprite ( diffId ) ;
diffSprite . difficultyId = diffId ;
grpDifficulties . add ( diffSprite ) ;
}
2023-01-23 00:55:30 +00:00
2023-03-16 01:05:15 +00:00
grpDifficulties . group . forEach ( function ( spr ) {
2023-01-23 00:55:30 +00:00
spr . visible = false ;
} ) ;
2023-10-12 07:20:21 +00:00
for ( diffSprite in grpDifficulties . group . members )
{
if ( diffSprite == null ) continue ;
if ( diffSprite . difficultyId == currentDifficulty ) diffSprite . visible = true ;
}
2023-01-23 00:55:30 +00:00
2024-03-28 05:46:50 +00:00
albumRoll . albumId = null ;
2024-03-20 18:37:24 +00:00
add ( albumRoll ) ;
2023-08-09 23:34:19 +00:00
2024-08-23 12:36:35 +00:00
albumRoll . applyExitMovers ( exitMovers , exitMoversCharSel ) ;
2023-08-09 23:34:19 +00:00
2024-08-23 12:36:35 +00:00
var overhangStuff: FlxSprite = new FlxSprite ( ) . makeGraphic ( FlxG . width , 164 , FlxColor . BLACK ) ;
2023-01-23 00:55:30 +00:00
overhangStuff . y -= overhangStuff . height ;
2024-08-23 12:36:35 +00:00
FlxTween . tween ( overhangStuff , { y : - 100 } , 0.3 , { ease : FlxEase . quartOut } ) ;
2023-01-23 00:55:30 +00:00
2024-03-20 18:37:24 +00: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-23 00:55:30 +00:00
fnfFreeplay . visible = false ;
2023-03-16 01:05:15 +00:00
2024-03-20 18:37:24 +00:00
ostName . font = ' V C R O S D M o n o ' ;
2024-01-11 05:30:00 +00:00
ostName . alignment = RIGHT ;
ostName . visible = false ;
2024-01-11 05:52:42 +00:00
exitMovers . set ( [ overhangStuff , fnfFreeplay , ostName ] ,
2023-03-16 01:05:15 +00:00
{
2023-03-16 04:17:52 +00:00
y : - overhangStuff . height ,
2023-03-16 01:05:15 +00:00
x : 0 ,
speed : 0.2 ,
wait : 0
} ) ;
2024-08-23 12:36:35 +00:00
exitMoversCharSel . set ( [ overhangStuff , fnfFreeplay , ostName ] ,
{
y : - 300 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2024-03-20 18:37:24 +00:00
var sillyStroke: StrokeShader = new StrokeShader ( 0xFFFFFFFF , 2 , 2 ) ;
2023-01-23 00:55:30 +00:00
fnfFreeplay . shader = sillyStroke ;
2024-04-30 07:22:30 +00:00
ostName . shader = sillyStroke ;
2023-01-23 00:55:30 +00:00
2024-01-11 05:30:00 +00:00
var fnfHighscoreSpr: FlxSprite = new FlxSprite ( 860 , 70 ) ;
2023-01-23 00:55:30 +00: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 18:37:24 +00: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-23 00:55:30 +00:00
fnfHighscoreSpr . visible = false ;
fnfHighscoreSpr . setGraphicSize ( 0 , Std . int ( fnfHighscoreSpr . height * 1 ) ) ;
fnfHighscoreSpr . updateHitbox ( ) ;
add ( fnfHighscoreSpr ) ;
2023-03-16 01:05:15 +00:00
new FlxTimer ( ) . start ( FlxG . random . float ( 12 , 50 ) , function ( tmr ) {
2024-03-20 18:37:24 +00:00
fnfHighscoreSpr . animation . play ( ' h i g h s c o r e ' ) ;
2023-01-23 00:55:30 +00:00
tmr . time = FlxG . random . float ( 20 , 60 ) ;
} , 0 ) ;
fp . visible = false ;
add ( fp ) ;
2024-01-11 05:30:00 +00: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 05:33:29 +00:00
clearBoxSprite . visible = false ;
2024-01-11 05:30:00 +00:00
add ( clearBoxSprite ) ;
2023-01-23 00:55:30 +00:00
txtCompletion . visible = false ;
add ( txtCompletion ) ;
2023-08-09 20:15:34 +00:00
add ( letterSort ) ;
letterSort . visible = false ;
exitMovers . set ( [ letterSort ] ,
{
y : - 100 ,
speed : 0.3
} ) ;
2024-08-23 12:36:35 +00:00
exitMoversCharSel . set ( [ letterSort ] ,
{
y : - 270 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2023-08-09 20:15:34 +00:00
letterSort . changeSelectionCallback = ( str ) - > {
switch ( str )
{
2024-03-20 18:37:24 +00:00
c ase ' f a v ' :
2023-08-09 20:15:34 +00:00
generateSongList ( { filterType : FAVORITE } , true ) ;
2024-03-20 18:37:24 +00:00
c ase ' A L L ' :
2023-08-09 23:34:19 +00:00
generateSongList ( null , true ) ;
2024-06-07 17:04:45 +00:00
c ase ' # ' :
generateSongList ( { filterType : REGEXP , filterData : ' 0 - 9 ' } , true ) ;
2023-08-09 20:15:34 +00:00
d efault :
generateSongList ( { filterType : REGEXP , filterData : str } , true ) ;
}
2024-04-29 07:49:28 +00: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 20:13:32 +00:00
FunkinSound . playOnce ( Paths . sound ( ' s c r o l l M e n u ' ) , 0.4 ) ;
2024-04-29 07:49:28 +00:00
curSelected = 1 ;
changeSelection ( ) ;
}
2023-08-09 20:15:34 +00:00
} ;
2024-04-30 05:33:29 +00:00
exitMovers . set ( [ fp , txtCompletion , fnfHighscoreSpr , txtCompletion , clearBoxSprite ] ,
2023-03-16 04:17:52 +00:00
{
x : FlxG . width ,
speed : 0.3
} ) ;
2024-08-23 12:36:35 +00:00
exitMoversCharSel . set ( [ fp , txtCompletion , fnfHighscoreSpr , txtCompletion , clearBoxSprite ] ,
{
y : - 270 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2024-04-24 23:45:17 +00: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 ) ;
2024-08-23 12:36:35 +00:00
// putting these here to fix the layering
add ( overhangStuff ) ;
add ( fnfFreeplay ) ;
add ( ostName ) ;
2024-04-24 23:45:17 +00:00
// 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 20:17:53 +00:00
var onDJIntroDone = function ( ) {
2023-08-09 23:34:19 +00:00
// when boyfriend hits dat shiii
2023-09-20 03:27:07 +00:00
2024-03-20 18:37:24 +00:00
albumRoll . playIntro ( ) ;
2023-08-09 23:34:19 +00:00
2023-01-23 00:55:30 +00:00
FlxTween . tween ( grpDifficulties , { x : 90 } , 0.6 , { ease : FlxEase . quartOut } ) ;
2024-04-24 23:45:17 +00:00
diffSelLeft . visible = true ;
diffSelRight . visible = true ;
2023-08-09 20:15:34 +00:00
letterSort . visible = true ;
2023-03-16 04:17:52 +00:00
exitMovers . set ( [ diffSelLeft , diffSelRight ] ,
{
x : - diffSelLeft . width * 2 ,
speed : 0.26
} ) ;
2023-01-23 00:55:30 +00:00
2024-08-23 12:36:35 +00:00
exitMoversCharSel . set ( [ diffSelLeft , diffSelRight ] ,
{
y : - 270 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2023-03-16 01:05:15 +00:00
new FlxTimer ( ) . start ( 1 / 24 , function ( handShit ) {
2023-01-23 00:55:30 +00:00
fnfHighscoreSpr . visible = true ;
fnfFreeplay . visible = true ;
2024-01-11 05:52:42 +00:00
ostName . visible = true ;
2023-01-23 00:55:30 +00:00
fp . visible = true ;
fp . updateScore ( 0 ) ;
2024-04-30 05:33:29 +00:00
clearBoxSprite . visible = true ;
2023-01-23 00:55:30 +00:00
txtCompletion . visible = true ;
intendedCompletion = 0 ;
2023-03-16 01:05:15 +00:00
new FlxTimer ( ) . start ( 1.5 / 24 , function ( bold ) {
2023-01-23 00:55:30 +00:00
sillyStroke . width = 0 ;
sillyStroke . height = 0 ;
2023-09-20 03:27:07 +00:00
changeSelection ( ) ;
2023-01-23 00:55:30 +00:00
} ) ;
} ) ;
bgDad . visible = true ;
2024-08-23 12:36:35 +00:00
backingCard ? . introDone ( ) ;
2024-05-30 03:34:00 +00:00
2024-05-14 00:20:23 +00:00
// render optimisation
2024-05-23 17:52:28 +00:00
if ( _parentState != null ) _parentState . persistentDraw = false ;
2024-06-08 01:13:13 +00:00
2024-06-20 20:17:53 +00:00
if ( prepForNewRank && fromResultsParams != null )
2024-05-30 09:25:51 +00:00
{
rankAnimStart ( fromResultsParams ) ;
}
2024-06-20 20:17:53 +00:00
} ;
2024-07-04 18:48:24 +00:00
if ( dj != null )
{
2024-06-20 20:17:53 +00:00
dj . onIntroDone . add ( onDJIntroDone ) ;
2024-07-04 18:48:24 +00:00
}
e lse
{
2024-06-20 20:17:53 +00:00
onDJIntroDone ( ) ;
}
2023-01-23 00:55:30 +00:00
2023-08-09 06:47:22 +00:00
generateSongList ( null , false ) ;
2023-01-23 00:55:30 +00:00
2024-04-24 23:45:17 +00:00
// dedicated camera for the state so we don't need to fuk around with camera scrolls from the mainmenu / elsewhere
2023-01-23 00:55:30 +00:00
funnyCam . bgColor = FlxColor . TRANSPARENT ;
2024-04-24 23:45:17 +00:00
FlxG . cameras . add ( funnyCam , false ) ;
2023-01-23 00:55:30 +00:00
2024-05-30 03:34:00 +00:00
rankVignette . scale . set ( 2 , 2 ) ;
rankVignette . updateHitbox ( ) ;
rankVignette . blend = BlendMode . ADD ;
// rankVignette.cameras = [rankCamera];
add ( rankVignette ) ;
rankVignette . alpha = 0 ;
2023-03-16 01:05:15 +00:00
forEach ( function ( bs ) {
2023-01-23 00:55:30 +00:00
bs . cameras = [ funnyCam ] ;
} ) ;
2024-05-30 03:34:00 +00:00
rankCamera . bgColor = FlxColor . TRANSPARENT ;
FlxG . cameras . add ( rankCamera , false ) ;
rankBg . cameras = [ rankCamera ] ;
rankBg . alpha = 0 ;
2024-05-31 09:39:53 +00:00
2024-06-02 06:53:07 +00:00
if ( prepForNewRank )
2024-05-31 09:39:53 +00:00
{
rankCamera . fade ( 0xFF000000 , 0 , false , null , true ) ;
}
2023-01-23 00:55:30 +00:00
}
2024-06-20 20:17:53 +00:00
var currentFilter: Null < SongFilter > = null ;
var currentFilteredSongs: Array < Null < FreeplaySongData > > = [ ] ;
2024-04-01 22:34:26 +00:00
2024-03-20 18:37:24 +00: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-17 02:12:07 +00:00
* @ param force Whether the capsules should " j u m p " back in or not using their animation
2024-04-01 22:34:26 +00: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 18:37:24 +00:00
* /
2024-04-01 22:34:26 +00:00
public function generateSongList ( filterStuff : Null < SongFilter > , force : Bool = false , onlyIfChanged : Bool = true ) : Void
2023-01-23 00:55:30 +00:00
{
2024-06-20 20:17:53 +00:00
var tempSongs: Array < Null < FreeplaySongData > > = songs ;
2023-01-23 00:55:30 +00:00
2024-04-30 18:36:57 +00:00
// Remember just the difficulty because it's important for song sorting.
if ( rememberedDifficulty != null )
{
currentDifficulty = rememberedDifficulty ;
}
2024-04-17 02:12:07 +00:00
if ( filterStuff != null ) tempSongs = sortSongs ( tempSongs , filterStuff ) ;
2023-01-23 00:55:30 +00:00
2024-04-01 22:34:26 +00: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 18:36:57 +00:00
// If curSelected is 0, the result will be null and fall back to the rememberedSongId.
2024-04-03 05:40:08 +00:00
rememberedSongId = grpCapsules . members [ curSelected ] ? . songData ? . songId ? ? rememberedSongId ;
2024-04-01 22:34:26 +00:00
for ( cap in grpCapsules . members )
{
2024-05-30 03:34:00 +00:00
cap . songText . resetText ( ) ;
2024-04-01 22:34:26 +00:00
cap . kill ( ) ;
}
currentFilter = filterStuff ;
currentFilteredSongs = tempSongs ;
curSelected = 0 ;
2023-08-28 18:52:03 +00:00
var hsvShader: HSVShader = new HSVShader ( ) ;
2023-08-09 06:47:22 +00:00
var randomCapsule: SongMenuItem = grpCapsules . recycle ( SongMenuItem ) ;
2023-10-17 00:12:40 +00:00
randomCapsule . init ( FlxG . width , 0 , null ) ;
2023-08-06 20:24:34 +00:00
randomCapsule . onConfirm = function ( ) {
2023-10-17 04:38:28 +00:00
capsuleOnConfirmRandom ( randomCapsule ) ;
2023-08-06 20:24:34 +00:00
} ;
randomCapsule . y = randomCapsule . intendedY ( 0 ) + 10 ;
randomCapsule . targetPos . x = randomCapsule . x ;
2024-05-30 03:34:00 +00:00
randomCapsule . alpha = 0 ;
2023-08-06 20:24:34 +00:00
randomCapsule . songText . visible = false ;
randomCapsule . favIcon . visible = false ;
2024-06-05 03:36:32 +00:00
randomCapsule . favIconBlurred . visible = false ;
2024-05-30 03:34:00 +00:00
randomCapsule . ranking . visible = false ;
randomCapsule . blurredRanking . visible = false ;
2023-08-06 20:24:34 +00:00
randomCapsule . initJumpIn ( 0 , force ) ;
2023-08-28 18:52:03 +00:00
randomCapsule . hsvShader = hsvShader ;
2023-08-06 20:24:34 +00:00
grpCapsules . add ( randomCapsule ) ;
2023-01-23 00:55:30 +00:00
for ( i in 0 ... tempSongs . length )
{
2024-06-20 20:17:53 +00:00
var tempSong = tempSongs [ i ] ;
if ( tempSong == null ) continue ;
2023-10-11 03:32:01 +00:00
2023-08-09 06:47:22 +00:00
var funnyMenu: SongMenuItem = grpCapsules . recycle ( SongMenuItem ) ;
2023-10-11 03:32:01 +00:00
2024-06-20 20:17:53 +00:00
funnyMenu . init ( FlxG . width , 0 , tempSong ) ;
2023-09-29 00:29:19 +00:00
funnyMenu . onConfirm = function ( ) {
capsuleOnConfirmDefault ( funnyMenu ) ;
} ;
2023-08-04 21:10:27 +00:00
funnyMenu . y = funnyMenu . intendedY ( i + 1 ) + 10 ;
2023-01-23 00:55:30 +00:00
funnyMenu . targetPos . x = funnyMenu . x ;
funnyMenu . ID = i ;
2023-09-19 23:10:30 +00:00
funnyMenu . capsule . alpha = 0.5 ;
2023-01-23 00:55:30 +00:00
funnyMenu . songText . visible = false ;
2024-06-20 20:17:53 +00:00
funnyMenu . favIcon . visible = tempSong . isFav ;
funnyMenu . favIconBlurred . visible = tempSong . isFav ;
2023-08-28 18:52:03 +00:00
funnyMenu . hsvShader = hsvShader ;
2023-01-23 00:55:30 +00:00
2024-05-30 03:34:00 +00:00
funnyMenu . newText . animation . curAnim . curFrame = 45 - ( ( i * 4 ) % 45 ) ;
funnyMenu . checkClip ( ) ;
2024-06-02 06:53:07 +00:00
funnyMenu . forcePosition ( ) ;
2024-05-30 03:34:00 +00:00
2023-01-23 00:55:30 +00:00
grpCapsules . add ( funnyMenu ) ;
}
2024-03-20 18:37:24 +00:00
FlxG . console . registerFunction ( ' c h a n g e S e l e c t i o n ' , changeSelection ) ;
2023-09-20 03:27:07 +00:00
2023-10-12 07:20:21 +00:00
rememberSelection ( ) ;
2023-01-23 00:55:30 +00:00
changeSelection ( ) ;
2024-04-30 18:36:57 +00:00
changeDiff ( 0 , true ) ;
2023-01-23 00:55:30 +00:00
}
2024-04-17 02:12:07 +00: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 20:17:53 +00:00
public function sortSongs ( songsToFilter : Array < Null < FreeplaySongData > > , songFilter : SongFilter ) : Array < Null < FreeplaySongData > >
2024-04-17 02:12:07 +00:00
{
2024-06-20 20:17:53 +00: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 20:24:24 +00:00
} ;
2024-04-17 02:12:07 +00: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 20:24:24 +00:00
songsToFilter . sort ( filterAlphabetically ) ;
2024-04-17 02:12:07 +00:00
c ase STARTSWITH :
// extra note: this is essentially a "search"
songsToFilter = songsToFilter . filter ( str - > {
if ( str == null ) return true ; // Random
2024-06-20 20:17:53 +00:00
return str . songName . toLowerCase ( ) . startsWith ( songFilter . filterData ? ? ' ' ) ;
2024-04-17 02:12:07 +00:00
} ) ;
c ase ALL :
2024-08-23 12:36:35 +00:00
// no filter!
2024-04-17 02:12:07 +00:00
c ase FAVORITE :
songsToFilter = songsToFilter . filter ( str - > {
if ( str == null ) return true ; // Random
return str . isFav ;
} ) ;
2024-06-04 20:24:24 +00:00
songsToFilter . sort ( filterAlphabetically ) ;
2024-04-17 02:12:07 +00:00
d efault :
// return all on default
}
2024-06-04 20:24:24 +00:00
2024-04-17 02:12:07 +00:00
return songsToFilter ;
}
2024-06-01 23:25:52 +00:00
var sparks: FlxSprite ;
var sparksADD: FlxSprite ;
2024-06-20 20:17:53 +00:00
function rankAnimStart ( fromResults : FromResultsParams ) : Void
2024-05-30 03:34:00 +00:00
{
2024-05-30 09:25:51 +00:00
busy = true ;
2024-06-06 00:49:33 +00:00
grpCapsules . members [ curSelected ] . sparkle . alpha = 0 ;
2024-05-31 09:39:53 +00:00
// grpCapsules.members[curSelected].forcePosition();
2024-05-30 09:25:51 +00:00
2024-06-20 20:17:53 +00:00
rememberedSongId = fromResults . songId ;
rememberedDifficulty = fromResults . difficultyId ;
changeSelection ( ) ;
changeDiff ( ) ;
2024-06-02 02:36:47 +00:00
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . fistPump ( ) ;
2024-05-30 03:34:00 +00:00
// rankCamera.fade(FlxColor.BLACK, 0.5, true);
rankCamera . fade ( 0xFF000000 , 0.5 , true , null , true ) ;
2024-05-31 06:30:42 +00:00
if ( FlxG . sound . music != null ) FlxG . sound . music . volume = 0 ;
2024-05-30 03:34:00 +00:00
rankBg . alpha = 1 ;
2024-06-20 20:17:53 +00:00
if ( fromResults . oldRank != null )
2024-06-01 23:25:52 +00: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 09:39:53 +00: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-30 03:34:00 +00:00
2024-06-01 23:25:52 +00:00
grpCapsules . members [ curSelected ] . ranking . visible = false ;
grpCapsules . members [ curSelected ] . blurredRanking . visible = false ;
2024-05-30 03:34:00 +00: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 09:39:53 +00: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-30 03:34:00 +00:00
( FlxG . height / 2 ) - ( grpCapsules . members [ curSelected ] . height / 2 ) ) ;
new FlxTimer ( ) . start ( 0.5 , _ - > {
2024-05-30 09:25:51 +00:00
rankDisplayNew ( fromResults ) ;
2024-05-30 03:34:00 +00:00
} ) ;
}
2024-05-30 09:25:51 +00:00
function rankDisplayNew ( fromResults : Null < FromResultsParams > ) : Void
2024-05-30 03:34:00 +00:00
{
2024-06-01 23:25:52 +00:00
grpCapsules . members [ curSelected ] . ranking . visible = true ;
grpCapsules . members [ curSelected ] . blurredRanking . visible = true ;
2024-05-30 03:34:00 +00:00
grpCapsules . members [ curSelected ] . ranking . scale . set ( 20 , 20 ) ;
grpCapsules . members [ curSelected ] . blurredRanking . scale . set ( 20 , 20 ) ;
2024-06-20 20:17:53 +00:00
if ( fromResults != null && fromResults . newRank != null )
2024-06-11 19:57:45 +00:00
{
2024-06-09 06:22:03 +00:00
grpCapsules . members [ curSelected ] . ranking . animation . play ( fromResults . newRank . getFreeplayRankIconAsset ( ) , true ) ;
}
2024-05-30 09:25:51 +00:00
2024-05-30 03:34:00 +00: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 20:17:53 +00:00
if ( fromResults != null && fromResults . newRank != null )
2024-06-11 19:57:45 +00:00
{
2024-06-09 06:22:03 +00:00
grpCapsules . members [ curSelected ] . blurredRanking . animation . play ( fromResults . newRank . getFreeplayRankIconAsset ( ) , true ) ;
}
2024-05-30 03:34:00 +00: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 23:25:52 +00: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 09:25:51 +00:00
switch ( fromResultsParams ? . newRank )
2024-05-30 03:34:00 +00:00
{
2024-05-30 09:25:51 +00:00
c ase SHIT :
2024-05-30 03:34:00 +00:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / r a n k i n b a d ' ) ) ;
2024-05-30 09:25:51 +00:00
c ase PERFECT :
2024-05-30 03:34:00 +00: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 09:25:51 +00:00
c ase PERFECT_GOLD :
2024-05-30 03:34:00 +00: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 09:25:51 +00:00
rankAnimSlam ( fromResults ) ;
2024-05-30 03:34:00 +00:00
} ) ;
}
2024-05-30 09:25:51 +00:00
function rankAnimSlam ( fromResultsParams : Null < FromResultsParams > )
2024-05-30 03:34:00 +00: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 09:25:51 +00:00
switch ( fromResultsParams ? . newRank )
2024-05-30 03:34:00 +00:00
{
2024-05-30 09:25:51 +00:00
c ase SHIT :
2024-05-30 03:34:00 +00:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / l o s s ' ) ) ;
2024-05-30 09:25:51 +00:00
c ase GOOD :
2024-05-30 03:34:00 +00:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / g o o d ' ) ) ;
2024-05-30 09:25:51 +00:00
c ase GREAT :
2024-05-30 03:34:00 +00:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / g r e a t ' ) ) ;
2024-05-30 09:25:51 +00:00
c ase EXCELLENT :
2024-05-30 03:34:00 +00:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / e x c e l l e n t ' ) ) ;
2024-05-30 09:25:51 +00:00
c ase PERFECT :
2024-05-30 03:34:00 +00:00
FunkinSound . playOnce ( Paths . sound ( ' r a n k s / p e r f e c t ' ) ) ;
2024-05-30 09:25:51 +00:00
c ase PERFECT_GOLD :
2024-05-30 03:34:00 +00: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 09:25:51 +00:00
if ( fromResultsParams ? . newRank == SHIT )
2024-05-30 03:34:00 +00:00
{
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . pumpFistBad ( ) ;
2024-05-30 03:34:00 +00:00
}
e lse
{
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . pumpFist ( ) ;
2024-05-30 03:34:00 +00: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 09:25:51 +00:00
// NOW we can interact with the menu
busy = false ;
2024-07-28 05:42:09 +00:00
capsule . sparkle . alpha = 0.7 ;
2024-06-06 00:49:33 +00:00
playCurSongPreview ( capsule ) ;
2024-05-30 03:34:00 +00: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 09:39:53 +00:00
prepForNewRank = false ;
2024-05-30 03:34:00 +00:00
} ) ;
}
2024-08-23 12:36:35 +00:00
function goToCharSelect ( ) : Void
{
var transitionGradient = new FlxSprite ( 0 , 720 ) . loadGraphic ( Paths . image ( ' f r e e p l a y / t r a n s i t i o n G r a d i e n t ' ) ) ;
transitionGradient . scale . set ( 1280 , 1 ) ;
transitionGradient . updateHitbox ( ) ;
transitionGradient . cameras = [ rankCamera ] ;
exitMoversCharSel . set ( [ transitionGradient ] ,
{
y : - 720 ,
speed : 0.8 ,
wait : 0.1
} ) ;
add ( transitionGradient ) ;
// busy = true;
for ( index => capsule in grpCapsules . members )
{
var distFromSelected: Float = Math . abs ( index - curSelected ) - 1 ;
if ( distFromSelected < 5 )
{
capsule . doLerp = false ;
exitMoversCharSel . set ( [ capsule ] ,
{
y : - 250 ,
speed : 0.8 ,
wait : 0.1
} ) ;
}
}
fadeShader . fade ( 1.0 , 0.0 , 0.8 , { ease : FlxEase . quadIn } ) ;
FlxG . sound . music . fadeOut ( 0.9 , 0 ) ;
// FlxTween.tween(transitionGradient, {y: 0}, 1, {ease: FlxEase.expoOut, startDelay: 0.3});
new FlxTimer ( ) . start ( 0.9 , _ - > {
FlxG . switchState ( new funkin . ui . charSelect . CharSelectSubState ( ) ) ;
} ) ;
for ( grpSpr in exitMoversCharSel . keys ( ) )
{
var moveData: Null < MoveData > = exitMoversCharSel . get ( grpSpr ) ;
if ( moveData == null ) continue ;
for ( spr in grpSpr )
{
if ( spr == null ) continue ;
var funnyMoveShit: MoveData = moveData ;
var moveDataX = funnyMoveShit . x ? ? spr . x ;
var moveDataY = funnyMoveShit . y ? ? spr . y ;
var moveDataSpeed = funnyMoveShit . speed ? ? 0.2 ;
var moveDataWait = funnyMoveShit . wait ? ? 0.0 ;
FlxTween . tween ( spr , { x : moveDataX , y : moveDataY + spr . y } , moveDataSpeed , { ease : FlxEase . backIn } ) ;
// longestTimer = Math.max(longestTimer, moveDataSpeed + moveDataWait);
}
}
}
2023-01-23 00:55:30 +00: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 09:25:51 +00:00
/ * *
* If true , disable interaction with the interface .
* /
var busy: Bool = false ;
2023-10-17 04:38:28 +00:00
2024-05-30 03:34:00 +00:00
var originalPos: FlxPoint = new FlxPoint ( ) ;
2024-03-12 03:42:32 +00:00
override function update ( elapsed : Float ) : Void
2023-01-23 00:55:30 +00:00
{
super . update ( elapsed ) ;
2024-08-23 12:36:35 +00:00
if ( FlxG . keys . justPressed . G )
2024-05-30 03:34:00 +00:00
{
2024-08-23 12:36:35 +00:00
goToCharSelect ( ) ;
2024-05-30 03:34:00 +00:00
}
2024-06-18 21:56:24 +00:00
if ( FlxG . keys . justPressed . P )
{
FlxG . switchState ( FreeplayState . build (
{
{
character : currentCharacterId == " p i c o " ? " b f " : " p i c o " ,
}
} ) ) ;
2024-05-30 03:34:00 +00:00
}
2024-08-23 12:36:35 +00:00
#if debug
if ( FlxG . keys . justPressed . T )
{
rankAnimStart ( fromResultsParams ? ?
{
playRankAnim : true ,
newRank : PERFECT_GOLD ,
songId : " t u t o r i a l " ,
difficultyId : " h a r d "
} ) ;
}
2024-06-01 23:25:52 +00:00
// if (FlxG.keys.justPressed.H)
// {
// rankDisplayNew(fromResultsParams);
// }
// if (FlxG.keys.justPressed.G)
// {
// rankAnimSlam(fromResultsParams);
// }
2024-05-30 09:25:51 +00:00
#end
2024-05-30 03:34:00 +00:00
2024-07-08 20:40:10 +00:00
if ( controls . FREEPLAY_CHAR_SELECT && ! busy )
2024-07-08 20:22:38 +00:00
{
FlxG . switchState ( new funkin . ui . charSelect . CharSelectSubState ( ) ) ;
}
2024-06-09 06:22:03 +00:00
if ( controls . FREEPLAY_FAVORITE && ! busy )
2023-01-23 00:55:30 +00:00
{
2024-04-01 22:34:26 +00:00
var targetSong = grpCapsules . members [ curSelected ] ? . songData ;
if ( targetSong != null )
2023-01-23 00:55:30 +00:00
{
2024-03-20 18:37:24 +00:00
var realShit: Int = curSelected ;
2024-05-21 06:49:07 +00:00
var isFav = targetSong . toggleFavorite ( ) ;
if ( isFav )
2023-10-11 03:32:01 +00:00
{
2024-05-31 09:39:53 +00:00
grpCapsules . members [ realShit ] . favIcon . visible = true ;
2024-06-05 03:36:32 +00:00
grpCapsules . members [ realShit ] . favIconBlurred . visible = true ;
2024-05-31 09:39:53 +00:00
grpCapsules . members [ realShit ] . favIcon . animation . play ( ' f a v ' ) ;
2024-06-05 03:36:32 +00:00
grpCapsules . members [ realShit ] . favIconBlurred . animation . play ( ' f a v ' ) ;
2024-05-31 09:39:53 +00:00
FunkinSound . playOnce ( Paths . sound ( ' f a v ' ) , 1 ) ;
2024-06-02 06:53:07 +00: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 09:39:53 +00: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-11 03:32:01 +00:00
{
2024-05-31 09:39:53 +00:00
ease : FlxEase . expoIn ,
startDelay : 0.1 ,
onComplete : function ( _ ) {
grpCapsules . members [ realShit ] . doLerp = true ;
busy = false ;
2023-10-11 03:32:01 +00:00
}
} ) ;
}
e lse
{
2024-05-31 09:39:53 +00:00
grpCapsules . members [ realShit ] . favIcon . animation . play ( ' f a v ' , true , true , 9 ) ;
2024-06-05 03:36:32 +00:00
grpCapsules . members [ realShit ] . favIconBlurred . animation . play ( ' f a v ' , true , true , 9 ) ;
2024-05-31 09:39:53 +00:00
FunkinSound . playOnce ( Paths . sound ( ' u n f a v ' ) , 1 ) ;
new FlxTimer ( ) . start ( 0.2 , _ - > {
2023-10-11 03:32:01 +00:00
grpCapsules . members [ realShit ] . favIcon . visible = false ;
2024-06-05 03:36:32 +00:00
grpCapsules . members [ realShit ] . favIconBlurred . visible = false ;
2024-06-02 06:53:07 +00:00
grpCapsules . members [ realShit ] . checkClip ( ) ;
2023-01-23 03:25:45 +00:00
} ) ;
2024-05-31 09:39:53 +00: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-11 03:32:01 +00:00
}
2023-01-23 00:55:30 +00:00
}
}
2024-05-08 05:54:48 +00:00
lerpScore = MathUtil . smoothLerp ( lerpScore , intendedScore , elapsed , 0.5 ) ;
lerpCompletion = MathUtil . smoothLerp ( lerpCompletion , intendedCompletion , elapsed , 0.5 ) ;
2023-01-23 00:55:30 +00:00
2024-01-11 05:30:00 +00:00
if ( Math . isNaN ( lerpScore ) )
{
lerpScore = intendedScore ;
}
if ( Math . isNaN ( lerpCompletion ) )
{
lerpCompletion = intendedCompletion ;
}
2023-01-23 00:55:30 +00:00
fp . updateScore ( Std . int ( lerpScore ) ) ;
2024-01-11 05:30:00 +00:00
txtCompletion . text = ' ${ Math . floor ( lerpCompletion * 100 ) } ' ;
// Right align the completion percentage
switch ( txtCompletion . text . length )
{
c ase 3 :
2024-04-30 05:33:29 +00:00
txtCompletion . offset . x = 10 ;
2024-01-11 05:30:00 +00:00
c ase 2 :
2024-04-30 05:33:29 +00:00
txtCompletion . offset . x = 0 ;
2024-01-11 05:30:00 +00:00
c ase 1 :
2024-04-30 05:33:29 +00:00
txtCompletion . offset . x = - 24 ;
2024-01-11 05:30:00 +00:00
d efault :
2024-04-30 05:33:29 +00:00
txtCompletion . offset . x = 0 ;
2024-01-11 05:30:00 +00:00
}
2023-01-23 00:55:30 +00:00
2023-10-17 04:38:28 +00:00
handleInputs ( elapsed ) ;
}
function handleInputs ( elapsed : Float ) : Void
{
if ( busy ) return ;
2023-01-23 00:55:30 +00:00
2024-06-18 21:56:24 +00:00
var upP: Bool = controls . UI_UP_P ;
var downP: Bool = controls . UI_DOWN_P ;
var accepted: Bool = controls . ACCEPT ;
2023-01-23 00:55:30 +00: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 18:37:24 +00:00
var dx: Float = initTouchPos . x - touch . screenX ;
var dy: Float = initTouchPos . y - touch . screenY ;
2023-01-23 00:55:30 +00:00
2024-03-20 18:37:24 +00:00
var angle: Float = Math . atan2 ( dy , dx ) ;
var length: Float = Math . sqrt ( dx * dx + dy * dy ) ;
2023-01-23 00:55:30 +00:00
2024-03-20 18:37:24 +00: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-23 00:55:30 +00:00
}
}
if ( FlxG . touches . getFirst ( ) != null )
{
2023-01-23 03:25:45 +00:00
if ( touchTimer >= 1.5 ) accepted = true ;
2023-01-23 00:55:30 +00: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-23 03:25:45 +00:00
if ( dxTouch != 0 ) dxTouch < 0 ? changeDiff ( 1 ) : changeDiff ( - 1 ) ;
2023-01-23 00:55:30 +00:00
}
if ( Math . abs ( dyTouch ) >= 100 )
{
touchY = touch . screenY ;
2023-01-23 03:25:45 +00:00
if ( dyTouch != 0 ) dyTouch < 0 ? changeSelection ( 1 ) : changeSelection ( - 1 ) ;
2023-01-23 00:55:30 +00:00
}
}
e lse
{
touchTimer = 0 ;
}
}
#if mobile
for ( touch in FlxG . touches . list )
{
if ( touch . justPressed )
{
// accepted = true;
}
}
#end
2024-06-18 21:56:24 +00:00
if ( ( controls . UI_UP || controls . UI_DOWN ) )
2023-01-23 00:55:30 +00:00
{
if ( spamming )
{
if ( spamTimer >= 0.07 )
{
spamTimer = 0 ;
2024-03-20 18:37:24 +00:00
if ( controls . UI_UP )
{
changeSelection ( - 1 ) ;
}
2023-01-23 00:55:30 +00:00
e lse
2024-03-20 18:37:24 +00:00
{
2023-01-23 00:55:30 +00:00
changeSelection ( 1 ) ;
2024-03-20 18:37:24 +00:00
}
2023-01-23 00:55:30 +00:00
}
}
2024-03-24 08:53:05 +00: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 20:17:53 +00:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2023-01-23 00:55:30 +00:00
}
e lse
{
spamming = false ;
spamTimer = 0 ;
}
2024-05-12 00:21:59 +00:00
#if ! html5
2023-01-23 00:55:30 +00:00
if ( FlxG . mouse . wheel != 0 )
{
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2024-05-11 23:35:04 +00:00
changeSelection ( - Math . round ( FlxG . mouse . wheel ) ) ;
2023-01-23 00:55:30 +00:00
}
2024-05-12 00:21:59 +00:00
#else
if ( FlxG . mouse . wheel < 0 )
{
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2024-05-15 01:21:47 +00:00
changeSelection ( - Math . round ( FlxG . mouse . wheel / 8 ) ) ;
2023-01-23 00:55:30 +00:00
}
2024-05-12 00:21:59 +00:00
e lse if ( FlxG . mouse . wheel > 0 )
{
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2024-05-12 00:21:59 +00:00
changeSelection ( - Math . round ( FlxG . mouse . wheel / 8 ) ) ;
}
#end
2023-01-23 00:55:30 +00:00
2024-06-18 21:56:24 +00:00
if ( controls . UI_LEFT_P )
2023-01-23 00:55:30 +00:00
{
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2023-01-23 00:55:30 +00:00
changeDiff ( - 1 ) ;
2024-04-01 22:34:26 +00:00
generateSongList ( currentFilter , true ) ;
2023-01-23 00:55:30 +00:00
}
2024-06-18 21:56:24 +00:00
if ( controls . UI_RIGHT_P )
2023-01-23 00:55:30 +00:00
{
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . resetAFKTimer ( ) ;
2023-01-23 00:55:30 +00:00
changeDiff ( 1 ) ;
2024-04-01 22:34:26 +00:00
generateSongList ( currentFilter , true ) ;
2023-01-23 00:55:30 +00:00
}
2024-05-03 01:23:55 +00:00
if ( controls . BACK )
2023-01-23 00:55:30 +00:00
{
2024-05-12 00:42:02 +00:00
busy = true ;
2023-03-17 02:02:56 +00:00
FlxTween . globalManager . clear ( ) ;
FlxTimer . globalManager . clear ( ) ;
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . onIntroDone . removeAll ( ) ;
2023-03-17 02:02:56 +00:00
2024-03-23 21:50:48 +00:00
FunkinSound . playOnce ( Paths . sound ( ' c a n c e l M e n u ' ) ) ;
2023-01-23 00:55:30 +00:00
2023-03-16 01:05:15 +00:00
var longestTimer: Float = 0 ;
2024-08-23 12:36:35 +00:00
backingCard ? . disappear ( ) ;
2024-05-31 09:39:53 +00:00
2023-03-16 04:17:52 +00:00
for ( grpSpr in exitMovers . keys ( ) )
2023-03-16 01:05:15 +00:00
{
2024-06-20 20:17:53 +00:00
var moveData: Null < MoveData > = exitMovers . get ( grpSpr ) ;
if ( moveData == null ) continue ;
2023-03-16 04:17:52 +00:00
for ( spr in grpSpr )
{
2024-03-28 05:46:50 +00:00
if ( spr == null ) continue ;
2023-03-16 04:17:52 +00:00
var funnyMoveShit: MoveData = moveData ;
2024-06-20 20:17:53 +00:00
var moveDataX = funnyMoveShit . x ? ? spr . x ;
var moveDataY = funnyMoveShit . y ? ? spr . y ;
var moveDataSpeed = funnyMoveShit . speed ? ? 0.2 ;
2024-07-29 21:26:49 +00:00
var moveDataWait = funnyMoveShit . wait ? ? 0.0 ;
2023-03-16 01:05:15 +00:00
2024-06-20 20:17:53 +00:00
FlxTween . tween ( spr , { x : moveDataX , y : moveDataY } , moveDataSpeed , { ease : FlxEase . expoIn } ) ;
2023-03-16 04:17:52 +00:00
2024-06-20 20:17:53 +00:00
longestTimer = Math . max ( longestTimer , moveDataSpeed + moveDataWait ) ;
2023-03-16 04:17:52 +00:00
}
2023-03-16 01:05:15 +00:00
}
for ( caps in grpCapsules . members )
{
caps . doJumpIn = false ;
caps . doLerp = false ;
caps . doJumpOut = true ;
}
2024-04-30 17:58:39 +00:00
if ( Type . getClass ( _parentState ) == MainMenuState )
2023-03-16 04:55:25 +00:00
{
2024-04-30 17:58:39 +00:00
_parentState . persistentUpdate = false ;
_parentState . persistentDraw = true ;
2023-03-16 04:55:25 +00:00
}
2023-03-16 01:05:15 +00:00
new FlxTimer ( ) . start ( longestTimer , ( _ ) - > {
FlxTransitionableState . skipNextTransIn = true ;
FlxTransitionableState . skipNextTransOut = true ;
2024-04-30 17:58:39 +00:00
if ( Type . getClass ( _parentState ) == MainMenuState )
2023-03-16 04:17:52 +00:00
{
2024-04-03 05:40:08 +00:00
FunkinSound . playMusic ( ' f r e a k y M e n u ' ,
{
overrideExisting : true ,
restartTrack : false
} ) ;
2024-06-02 00:36:14 +00:00
FlxG . sound . music . fadeIn ( 4.0 , 0.0 , 1.0 ) ;
2023-03-16 04:17:52 +00:00
close ( ) ;
}
e lse
{
2024-02-06 02:35:58 +00:00
FlxG . switchState ( ( ) - > new MainMenuState ( ) ) ;
2023-03-16 04:17:52 +00:00
}
2023-03-16 01:05:15 +00:00
} ) ;
2023-01-23 00:55:30 +00:00
}
if ( accepted )
{
2023-08-06 20:24:34 +00:00
grpCapsules . members [ curSelected ] . onConfirm ( ) ;
2023-01-23 00:55:30 +00:00
}
}
2023-12-16 02:09:01 +00:00
public override function destroy ( ) : Void
2023-01-23 00:55:30 +00:00
{
2023-12-16 02:09:01 +00:00
super . destroy ( ) ;
2024-04-03 05:01:58 +00:00
var daSong: Null < FreeplaySongData > = currentFilteredSongs [ curSelected ] ;
2023-10-11 03:32:01 +00:00
if ( daSong != null )
{
clearDaCache ( daSong . songName ) ;
}
2024-05-14 00:20:23 +00:00
// remove and destroy freeplay camera
2024-05-14 00:30:36 +00:00
FlxG . cameras . remove ( funnyCam ) ;
2023-01-23 00:55:30 +00:00
}
2024-04-30 18:36:57 +00:00
function changeDiff ( change : Int = 0 , force : Bool = false ) : Void
2023-01-23 00:55:30 +00:00
{
touchTimer = 0 ;
2024-03-20 18:37:24 +00:00
var currentDifficultyIndex: Int = diffIdsCurrent . indexOf ( currentDifficulty ) ;
2023-01-23 00:55:30 +00:00
2023-10-12 07:20:21 +00:00
if ( currentDifficultyIndex == - 1 ) currentDifficultyIndex = diffIdsCurrent . indexOf ( Constants . DEFAULT_DIFFICULTY ) ;
2023-01-23 00:55:30 +00:00
2023-10-12 07:20:21 +00:00
currentDifficultyIndex += change ;
if ( currentDifficultyIndex < 0 ) currentDifficultyIndex = diffIdsCurrent . length - 1 ;
if ( currentDifficultyIndex >= diffIdsCurrent . length ) currentDifficultyIndex = 0 ;
currentDifficulty = diffIdsCurrent [ currentDifficultyIndex ] ;
2023-10-03 23:14:46 +00:00
2024-04-01 22:34:26 +00:00
var daSong: Null < FreeplaySongData > = grpCapsules . members [ curSelected ] . songData ;
2023-10-11 03:32:01 +00:00
if ( daSong != null )
{
2024-06-20 20:17:53 +00:00
var targetSong: Null < Song > = SongRegistry . instance . fetchEntry ( daSong . songId ) ;
2024-06-11 04:40:43 +00:00
if ( targetSong == null )
{
2024-06-20 20:17:53 +00: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 04:40:43 +00:00
return ;
}
2024-06-20 20:17:53 +00:00
var targetVariation: String = targetSong . getFirstValidVariation ( currentDifficulty ) ? ? ' ' ;
2024-06-11 04:40:43 +00: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 20:17:53 +00:00
var songScore: Null < SaveScoreData > = Save . instance . getSongScore ( daSong . songId , suffixedDifficulty ) ;
2023-10-11 03:32:01 +00:00
intendedScore = songScore ? . score ? ? 0 ;
2024-05-18 00:26:34 +00:00
intendedCompletion = songScore == null ? 0.0 : ( ( songScore . tallies . sick + songScore . tallies . good ) / songScore . tallies . totalNotes ) ;
2023-10-12 07:20:21 +00:00
rememberedDifficulty = currentDifficulty ;
2023-10-11 03:32:01 +00:00
}
e lse
{
intendedScore = 0 ;
intendedCompletion = 0.0 ;
}
2023-01-23 00:55:30 +00:00
2024-01-11 05:30:00 +00:00
if ( intendedCompletion == Math . POSITIVE_INFINITY || intendedCompletion == Math . NEGATIVE_INFINITY || Math . isNaN ( intendedCompletion ) )
{
intendedCompletion = 0 ;
}
2023-10-12 07:20:21 +00:00
grpDifficulties . group . forEach ( function ( diffSprite ) {
diffSprite . visible = false ;
2023-01-23 00:55:30 +00:00
} ) ;
2023-10-12 07:20:21 +00: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 05:30:00 +00:00
2024-04-30 18:36:57 +00:00
if ( change != 0 || force )
2024-01-11 05:30:00 +00: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 22:21:57 +00:00
songCapsule . checkClip ( ) ;
2024-01-11 05:30:00 +00:00
}
e lse
{
songCapsule . init ( null , null , null ) ;
}
}
2024-07-28 05:42:09 +00:00
// Reset the song preview in case we changed variations (normal->erect etc)
playCurSongPreview ( ) ;
2024-01-11 05:30:00 +00:00
}
2024-03-23 22:22:15 +00:00
// Set the album graphic and play the animation if relevant.
2024-06-20 20:17:53 +00:00
var newAlbumId: Null < String > = daSong ? . albumId ;
2024-03-23 22:22:15 +00:00
if ( albumRoll . albumId != newAlbumId )
{
albumRoll . albumId = newAlbumId ;
2024-03-30 04:54:07 +00:00
albumRoll . skipIntro ( ) ;
2024-03-23 22:22:15 +00:00
}
2024-05-11 05:05:51 +00:00
// Set difficulty star count.
albumRoll . setDifficultyStars ( daSong ? . difficultyRating ) ;
2023-01-23 00:55:30 +00: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 18:37:24 +00:00
function clearDaCache ( actualSongTho : String ) : Void
2023-01-23 00:55:30 +00:00
{
for ( song in songs )
{
2023-10-17 04:38:28 +00:00
if ( song == null ) continue ;
2023-01-23 00:55:30 +00: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-17 00:12:40 +00:00
function capsuleOnConfirmRandom ( randomCapsule : SongMenuItem ) : Void
2023-08-06 20:24:34 +00:00
{
2024-03-20 18:37:24 +00:00
trace ( ' R A N D O M S E L E C T E D ' ) ;
2023-08-06 20:24:34 +00:00
2023-10-17 04:38:28 +00:00
busy = true ;
2023-11-07 23:53:50 +00:00
letterSort . inputEnabled = false ;
2023-10-17 00:12:40 +00: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 20:17:53 +00:00
return cap ? . songData ? . songName ;
2023-10-17 00:12:40 +00:00
} ) } ' ) ;
2023-11-07 23:53:50 +00:00
if ( availableSongCapsules . length == 0 )
{
2024-03-20 18:37:24 +00:00
trace ( ' N o s o n g s a v a i l a b l e ! ' ) ;
2023-11-07 23:53:50 +00:00
busy = false ;
letterSort . inputEnabled = true ;
2024-03-23 21:50:48 +00:00
FunkinSound . playOnce ( Paths . sound ( ' c a n c e l M e n u ' ) ) ;
2023-11-07 23:53:50 +00:00
return ;
}
2023-10-17 00:12:40 +00: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 04:38:28 +00:00
}
2023-09-29 00:29:19 +00:00
function capsuleOnConfirmDefault ( cap : SongMenuItem ) : Void
2023-01-23 00:55:30 +00:00
{
2023-10-17 04:38:28 +00:00
busy = true ;
2023-11-07 23:53:50 +00:00
letterSort . inputEnabled = false ;
2023-08-06 20:24:34 +00:00
PlayStatePlaylist . isStoryMode = false ;
2023-01-23 00:55:30 +00:00
2024-06-20 20:17:53 +00: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-29 01:52:45 +00:00
{
2024-06-20 20:17:53 +00: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-29 01:52:45 +00:00
return ;
}
2024-06-20 20:17:53 +00:00
var targetSong: Song = targetSongNullable ;
2024-06-07 01:38:00 +00:00
var targetDifficultyId: String = currentDifficulty ;
2024-06-20 20:17:53 +00:00
var targetVariation: Null < String > = targetSong . getFirstValidVariation ( targetDifficultyId , currentCharacter ) ;
var targetLevelId: Null < String > = cap ? . songData ? . levelId ;
PlayStatePlaylist . campaignId = targetLevelId ? ? null ;
2023-08-06 20:24:34 +00:00
2024-06-20 20:17:53 +00:00
var targetDifficulty: Null < SongDifficulty > = targetSong . getDifficulty ( targetDifficultyId , targetVariation ) ;
2024-06-07 01:38:00 +00: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 21:56:24 +00: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-07 01:38:00 +00:00
2023-08-06 20:24:34 +00:00
// Visual and audio effects.
2024-03-23 21:50:48 +00:00
FunkinSound . playOnce ( Paths . sound ( ' c o n f i r m M e n u ' ) ) ;
2024-06-20 20:17:53 +00:00
if ( dj != null ) dj . confirm ( ) ;
2023-08-06 20:24:34 +00:00
2024-05-31 09:39:53 +00:00
grpCapsules . members [ curSelected ] . forcePosition ( ) ;
2024-06-27 23:50:38 +00:00
grpCapsules . members [ curSelected ] . confirm ( ) ;
2024-05-30 03:34:00 +00:00
2024-08-23 12:36:35 +00:00
backingCard ? . confirm ( ) ;
2024-05-30 03:34:00 +00:00
2023-08-06 20:24:34 +00:00
new FlxTimer ( ) . start ( 1 , function ( tmr : FlxTimer ) {
2024-06-05 19:02:29 +00:00
FunkinSound . emptyPartialQueue ( ) ;
2024-06-20 20:17:53 +00:00
Paths . setCurrentLevel ( cap ? . songData ? . levelId ) ;
2024-02-17 04:48:43 +00:00
LoadingState . loadPlayState (
2023-08-06 20:24:34 +00:00
{
targetSong : targetSong ,
2024-06-07 01:38:00 +00:00
targetDifficulty : targetDifficultyId ,
2024-02-06 02:35:58 +00:00
targetVariation : targetVariation ,
2024-06-07 01:38:00 +00:00
targetInstrumental : targetInstId ,
2024-02-29 23:49:20 +00:00
practiceMode : false ,
minimalMode : false ,
2024-04-01 22:34:26 +00:00
#if ( debug || FORCE_DEBUG_VERSION )
botPlayMode : FlxG . keys . pressed . SHIFT ,
#else
botPlayMode : false ,
#end
2024-03-06 03:27:07 +00:00
// TODO: Make these an option! It's currently only accessible via chart editor.
// startTimestamp: 0.0,
// playbackRate: 0.5,
// botPlayMode: true,
2024-02-17 04:48:43 +00:00
} , true ) ;
2023-08-06 20:24:34 +00:00
} ) ;
}
2023-10-12 07:20:21 +00:00
function rememberSelection ( ) : Void
{
if ( rememberedSongId != null )
{
2024-04-01 22:34:26 +00:00
curSelected = currentFilteredSongs . findIndex ( function ( song ) {
2023-10-12 07:20:21 +00:00
if ( song == null ) return false ;
return song . songId == rememberedSongId ;
} ) ;
2024-04-01 22:34:26 +00:00
if ( curSelected == - 1 ) curSelected = 0 ;
2023-10-12 07:20:21 +00:00
}
if ( rememberedDifficulty != null )
{
currentDifficulty = rememberedDifficulty ;
}
}
2024-03-12 03:42:32 +00:00
function changeSelection ( change : Int = 0 ) : Void
2023-01-23 00:55:30 +00:00
{
2024-03-20 18:37:24 +00:00
var prevSelected: Int = curSelected ;
2023-10-17 00:12:40 +00:00
2023-01-23 00:55:30 +00:00
curSelected += change ;
2024-06-10 16:04:18 +00:00
if ( ! prepForNewRank && curSelected != prevSelected ) FunkinSound . playOnce ( Paths . sound ( ' s c r o l l M e n u ' ) , 0.4 ) ;
2023-08-09 07:03:58 +00:00
if ( curSelected < 0 ) curSelected = grpCapsules . countLiving ( ) - 1 ;
if ( curSelected >= grpCapsules . countLiving ( ) ) curSelected = 0 ;
2023-01-23 00:55:30 +00:00
2024-03-20 18:37:24 +00:00
var daSongCapsule: SongMenuItem = grpCapsules . members [ curSelected ] ;
2023-10-17 00:12:40 +00:00
if ( daSongCapsule . songData != null )
2023-08-09 07:03:58 +00:00
{
2024-06-20 20:17:53 +00:00
var songScore: Null < SaveScoreData > = Save . instance . getSongScore ( daSongCapsule . songData . songId , currentDifficulty ) ;
2023-10-11 03:32:01 +00:00
intendedScore = songScore ? . score ? ? 0 ;
2024-05-18 00:26:34 +00:00
intendedCompletion = songScore == null ? 0.0 : ( ( songScore . tallies . sick + songScore . tallies . good ) / songScore . tallies . totalNotes ) ;
2023-11-02 03:20:47 +00:00
diffIdsCurrent = daSongCapsule . songData . songDifficulties ;
rememberedSongId = daSongCapsule . songData . songId ;
2023-10-12 07:20:21 +00:00
changeDiff ( ) ;
2023-08-09 07:03:58 +00:00
}
e lse
{
intendedScore = 0 ;
2023-10-11 03:32:01 +00:00
intendedCompletion = 0.0 ;
2024-04-01 22:34:26 +00:00
diffIdsCurrent = diffIdsTotal ;
2023-10-12 07:20:21 +00:00
rememberedSongId = null ;
rememberedDifficulty = null ;
2024-03-28 05:46:50 +00:00
albumRoll . albumId = null ;
2023-08-09 07:03:58 +00:00
}
2023-01-23 00:55:30 +00:00
for ( index => capsule in grpCapsules . members )
{
2023-08-04 19:59:17 +00:00
index += 1 ;
2023-01-23 00:55:30 +00:00
2023-09-20 03:27:07 +00:00
capsule . selected = index == curSelected + 1 ;
2023-01-23 00:55:30 +00:00
2023-08-04 21:10:27 +00:00
capsule . targetPos . y = capsule . intendedY ( index - curSelected ) ;
2023-01-23 00:55:30 +00:00
capsule . targetPos . x = 270 + ( 60 * ( Math . sin ( index - curSelected ) ) ) ;
2023-01-23 03:25:45 +00:00
if ( index < curSelected ) capsule . targetPos . y -= 100 ; // another 100 for good measure
2023-01-23 00:55:30 +00:00
}
2024-06-06 00:49:33 +00:00
if ( grpCapsules . countLiving ( ) > 0 && ! prepForNewRank )
2023-08-14 02:12:08 +00:00
{
2024-06-06 00:49:33 +00:00
playCurSongPreview ( daSongCapsule ) ;
2023-08-14 02:12:08 +00:00
grpCapsules . members [ curSelected ] . selected = true ;
}
2023-01-23 00:55:30 +00:00
}
2024-03-29 02:33:50 +00:00
2024-07-28 05:42:09 +00:00
public function playCurSongPreview ( ? daSongCapsule : SongMenuItem ) : Void
2024-06-06 00:49:33 +00:00
{
2024-07-28 05:42:09 +00:00
if ( daSongCapsule == null ) daSongCapsule = grpCapsules . members [ curSelected ] ;
2024-06-06 00:49:33 +00: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 20:17:53 +00:00
var previewSongId: Null < String > = daSongCapsule ? . songData ? . songId ;
if ( previewSongId == null ) return ;
var previewSong: Null < Song > = SongRegistry . instance . fetchEntry ( previewSongId ) ;
2024-06-18 21:56:24 +00: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 16:42:27 +00:00
instSuffix = ( instSuffix != ' ' ) ? ' - $ instSuffix ' : ' ' ;
2024-06-18 21:56:24 +00:00
2024-06-20 20:17:53 +00: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-06 00:49:33 +00:00
{
startingVolume : 0.0 ,
overrideExisting : true ,
restartTrack : false ,
2024-06-17 16:22:49 +00:00
mapTimeChanges : false , // The music metadata is not alongside the audio file so this won't work.
2024-06-06 00:49:33 +00:00
pathsFunction : INST ,
2024-06-10 16:42:27 +00:00
suffix : instSuffix ,
2024-06-06 00:49:33 +00:00
partialParams :
{
loadPartial : true ,
start : 0.05 ,
end : 0.25
} ,
onLoad : function ( ) {
FlxG . sound . music . fadeIn ( 2 , 0 , 0.4 ) ;
}
} ) ;
}
}
2024-03-29 02:33:50 +00: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 09:39:53 +00:00
var result: MainMenuState ;
2024-06-20 20:17:53 +00: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 23:25:52 +00:00
e lse
2024-05-31 09:39:53 +00:00
result = new MainMenuState ( false ) ;
2024-03-29 02:33:50 +00:00
result . openSubState ( new FreeplayState ( params , stickers ) ) ;
2024-05-01 19:22:20 +00:00
result . persistentUpdate = false ;
result . persistentDraw = true ;
2024-03-29 02:33:50 +00:00
return result ;
}
2021-12-08 00:29:26 +00:00
}
2024-03-20 18:37:24 +00:00
/ * *
* The difficulty selector arrows to the left and right of the difficulty .
* /
2021-12-08 00:29:26 +00:00
class DifficultySelector extends FlxSprite
{
2023-01-23 00:55:30 +00:00
var controls: Controls ;
var whiteShader: PureColor ;
2021-12-08 00:29:26 +00:00
2023-01-23 00:55:30 +00:00
public function n e w ( x : Float , y : Float , flipped : Bool , controls : Controls )
{
super ( x , y ) ;
2021-12-08 00:29:26 +00:00
2023-01-23 00:55:30 +00:00
this . controls = controls ;
2021-12-08 00:29:26 +00:00
2023-01-23 00:55:30 +00: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 18:37:24 +00: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-23 00:55:30 +00:00
animation . play ( ' s h i n e ' ) ;
2021-12-08 00:29:26 +00:00
2023-01-23 00:55:30 +00:00
whiteShader = new PureColor ( FlxColor . WHITE ) ;
2021-12-08 03:34:01 +00:00
2023-01-23 00:55:30 +00:00
shader = whiteShader ;
2021-12-08 03:34:01 +00:00
2023-01-23 00:55:30 +00:00
flipX = flipped ;
}
2021-04-08 21:29:31 +00:00
2024-03-12 03:42:32 +00:00
override function update ( elapsed : Float ) : Void
2023-01-23 00:55:30 +00:00
{
2024-06-18 21:56:24 +00:00
if ( flipX && controls . UI_RIGHT_P ) moveShitDown ( ) ;
if ( ! flipX && controls . UI_LEFT_P ) moveShitDown ( ) ;
2021-12-08 00:29:26 +00:00
2023-01-23 00:55:30 +00:00
super . update ( elapsed ) ;
}
2021-12-08 00:29:26 +00:00
2024-03-12 03:42:32 +00:00
function moveShitDown ( ) : Void
2023-01-23 00:55:30 +00:00
{
offset . y -= 5 ;
2021-04-08 21:29:31 +00:00
2023-01-23 00:55:30 +00:00
whiteShader . colorSet = true ;
2021-12-08 03:34:01 +00:00
2023-08-07 02:20:18 +00:00
scale . x = scale . y = 0.5 ;
2023-03-16 01:05:15 +00:00
new FlxTimer ( ) . start ( 2 / 24 , function ( tmr ) {
2023-08-07 02:20:18 +00:00
scale . x = scale . y = 1 ;
2023-01-23 00:55:30 +00:00
whiteShader . colorSet = false ;
updateHitbox ( ) ;
} ) ;
}
2020-10-21 18:05:27 +00:00
}
2021-02-25 01:52:59 +00:00
2024-03-20 18:37:24 +00: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 06:50:53 +00:00
typedef SongFilter =
{
2023-01-23 00:55:30 +00:00
var filterType: FilterType ;
var ? filterData: Dynamic ;
2022-09-28 06:50:53 +00:00
}
2024-03-20 18:37:24 +00:00
/ * *
* Possible types to use for t h e s o n g f i l t e r .
* /
2022-09-28 06:50:53 +00:00
enum a b s t r a c t FilterType ( S t r i n g )
{
2024-03-20 18:37:24 +00: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 06:50:53 +00:00
}
2024-03-20 18:37:24 +00:00
/ * *
* Data about a specific song in the freeplay menu .
* /
2023-06-09 22:25:21 +00:00
class FreeplaySongData
2021-02-25 01:52:59 +00:00
{
2024-03-20 18:37:24 +00:00
/ * *
* Whether or not the song has been favorited .
* /
2023-10-12 07:20:21 +00:00
public var isFav: Bool = false ;
2024-06-06 00:49:33 +00:00
public var isNew: Bool = false ;
2024-01-11 05:30:00 +00:00
var song: Song ;
2024-03-20 18:37:24 +00:00
public var levelId( default , null ) : String = ' ' ;
public var songId( default , null ) : String = ' ' ;
2024-01-11 05:30:00 +00:00
public var songDifficulties( default , null ) : Array < String > = [ ] ;
2023-01-23 00:55:30 +00:00
2024-03-20 18:37:24 +00:00
public var songName( default , null ) : String = ' ' ;
public var songCharacter( default , null ) : String = ' ' ;
2024-05-30 03:34:00 +00:00
public var songStartingBpm( default , null ) : Float = 0 ;
2024-05-11 05:05:51 +00:00
public var difficultyRating( default , null ) : Int = 0 ;
2024-03-28 05:46:50 +00:00
public var albumId( default , null ) : Null < String > = null ;
2024-01-11 05:30:00 +00:00
public var currentDifficulty( default , set ) : String = Constants . DEFAULT_DIFFICULTY ;
2024-05-11 05:05:51 +00:00
2024-05-30 09:25:51 +00:00
public var scoringRank: Null < ScoringRank > = null ;
2024-05-11 05:05:51 +00:00
var displayedVariations: Array < String > = [ Constants . DEFAULT_VARIATION ] ;
2024-01-11 05:30:00 +00:00
function set_currentDifficulty ( value : String ) : String
{
2024-06-08 22:29:55 +00:00
if ( currentDifficulty == value ) return value ;
2024-01-11 05:30:00 +00:00
currentDifficulty = value ;
2024-02-06 02:35:58 +00:00
updateValues ( displayedVariations ) ;
2024-01-11 05:30:00 +00:00
return value ;
}
2024-02-06 02:35:58 +00:00
public function n e w ( levelId : String , songId : String , song : Song , ? displayedVariations : Array < String > )
2023-01-23 00:55:30 +00:00
{
2023-06-09 22:25:21 +00:00
this . levelId = levelId ;
2024-01-11 05:30:00 +00:00
this . songId = songId ;
this . song = song ;
2024-05-21 06:49:07 +00:00
this . isFav = Save . instance . isSongFavorited ( songId ) ;
2024-02-06 02:35:58 +00:00
if ( displayedVariations != null ) this . displayedVariations = displayedVariations ;
2024-01-11 05:30:00 +00:00
2024-02-06 02:35:58 +00:00
updateValues ( displayedVariations ) ;
2024-01-11 05:30:00 +00:00
}
2024-05-21 06:49:07 +00: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 18:37:24 +00:00
function updateValues ( variations : Array < String > ) : Void
2024-01-11 05:30:00 +00:00
{
2024-07-28 05:42:09 +00:00
this . songDifficulties = song . listSuffixedDifficulties ( variations , false , false ) ;
2024-01-11 05:30:00 +00:00
if ( ! this . songDifficulties . contains ( currentDifficulty ) ) currentDifficulty = Constants . DEFAULT_DIFFICULTY ;
2024-06-07 18:24:57 +00:00
var songDifficulty: SongDifficulty = song . getDifficulty ( currentDifficulty , null , variations ) ;
2024-01-11 05:30:00 +00:00
if ( songDifficulty == null ) return ;
2024-05-30 03:34:00 +00:00
this . songStartingBpm = songDifficulty . getStartingBPM ( ) ;
2024-01-11 05:30:00 +00:00
this . songName = songDifficulty . songName ;
this . songCharacter = songDifficulty . characters . opponent ;
2024-05-11 05:05:51 +00:00
this . difficultyRating = songDifficulty . difficultyRating ;
2024-03-28 05:46:50 +00: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 09:25:51 +00:00
2024-06-14 13:53:33 +00: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 09:25:51 +00:00
2024-06-14 13:53:33 +00:00
this . scoringRank = Save . instance . getSongRank ( songId , suffixedDifficulty ) ;
2024-06-06 00:49:33 +00:00
this . isNew = song . isSongNew ( currentDifficulty ) ;
2023-01-23 00:55:30 +00:00
}
2021-02-25 01:52:59 +00:00
}
2023-03-16 01:05:15 +00:00
2024-03-20 18:37:24 +00: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-16 01:05:15 +00:00
typedef MoveData =
{
2023-03-16 04:17:52 +00:00
var ? x: Float ;
var ? y: Float ;
var ? speed: Float ;
var ? wait: Float ;
2023-03-16 01:05:15 +00:00
}
2023-10-12 07:20:21 +00:00
2024-03-20 18:37:24 +00:00
/ * *
* The sprite for t h e d i f f i c u l t y
* /
2023-10-12 07:20:21 +00:00
class DifficultySprite extends FlxSprite
{
2024-03-20 18:37:24 +00:00
/ * *
* The difficulty id which this sprite represents .
* /
2023-10-12 07:20:21 +00:00
public var difficultyId: String ;
public function n e w ( diffId : String )
{
super ( ) ;
difficultyId = diffId ;
2024-07-28 05:42:09 +00: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 16:12:50 +00:00
{
2024-07-28 05:42:09 +00: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 16:12:50 +00: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 05:42:09 +00: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 16:12:50 +00:00
}
2023-10-12 07:20:21 +00:00
}
}