2023-11-07 09:04:22 +00:00
package funkin . ui . freeplay ;
2021-04-08 00:19:49 +00:00
2024-08-30 00:04:30 +00:00
import funkin . ui . freeplay . backcards . * ;
2023-10-11 03:32:01 +00:00
import flixel . addons . transition . FlxTransitionableState ;
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 ;
2024-09-12 21:44:40 +00:00
import flixel . math . FlxMath ;
2021-08-24 19:28:04 +00:00
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 ;
import openfl . display . BlendMode ;
2024-08-30 00:04:30 +00:00
import funkin . data . freeplay . style . FreeplayStyleRegistry ;
import funkin . data . song . SongData . SongMusicData ;
2024-09-19 14:03:16 +00:00
#if FEATURE_DISCORD_RPC
import funkin . api . discord . DiscordClient ;
#end
2020-10-21 18:05:27 +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 > > = [ ] ;
2023-01-23 00:55:30 +00:00
var curSelected: Int = 0 ;
2024-09-27 18:26:08 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* Currently selected difficulty , i n string form .
* /
var currentDifficulty: String = Constants . DEFAULT_DIFFICULTY ;
2024-09-27 18:26:08 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* Current variation : d efault , erect , pico , bf , etc .
* /
var currentVariation: String = Constants . DEFAULT_VARIATION ;
2020-11-07 02:17:27 +00:00
2024-08-30 00:04:30 +00:00
public 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 ;
2024-09-12 21:44:40 +00:00
var charSelectHint: FlxText ;
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-07-15 10:30:10 +00:00
/ * *
* The difficulty we were on when this menu was last accessed .
* /
public static var rememberedDifficulty: String = Constants . DEFAULT_DIFFICULTY ;
/ * *
* The song we were on when this menu was last accessed .
* NOTE : ` null ` if t h e l a s t s o n g w a s ` R a n d o m ` .
* /
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-07-15 10:30:10 +00:00
/ * *
* The character we were on when this menu was last accessed .
* /
public static var rememberedCharacterId: String = Constants . DEFAULT_CHARACTER ;
2024-10-02 00:32:48 +00:00
/ * *
* The remembered variation we were on when this menu was last accessed .
* /
public static var rememberedVariation: String = Constants . DEFAULT_VARIATION ;
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-10-02 00:32:48 +00:00
/ * *
* The backing card that has the toned dots , right now we just use that one dad graphic dave cooked up
* /
2024-08-23 12:36:35 +00:00
public var bgDad: FlxSprite ;
2024-05-30 03:34:00 +00:00
2024-10-02 00:32:48 +00:00
public var angleMaskShader: AngleMask = new AngleMask ( ) ;
2024-05-30 09:25:51 +00:00
2024-10-02 00:32:48 +00:00
var fadeShader: BlueFade = new BlueFade ( ) ;
2024-05-31 09:39:53 +00:00
2024-10-02 00:32:48 +00:00
var fromResultsParams: Null < FromResultsParams > = null ;
var prepForNewRank: Bool = false ;
2024-08-30 00:04:30 +00:00
var styleData: Null < FreeplayStyle > = null ;
2024-10-02 00:32:48 +00:00
var fromCharSelect: Bool = false ;
2024-08-30 00:04:30 +00:00
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-07-15 10:30:10 +00:00
currentCharacterId = params ? . character ? ? rememberedCharacterId ;
2024-08-30 00:04:30 +00:00
styleData = FreeplayStyleRegistry . instance . fetchEntry ( currentCharacterId ) ;
2024-10-02 00:32:48 +00:00
2024-06-20 20:17:53 +00:00
var fetchPlayableCharacter = function ( ) : PlayableCharacter {
2024-09-01 07:22:34 +00:00
var targetCharId = params ? . character ? ? rememberedCharacterId ;
var result = PlayerRegistry . instance . fetchEntry ( targetCharId ) ;
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 ${ targetCharId } ' ;
2024-06-20 20:17:53 +00:00
return result ;
} ;
2024-02-05 18:35:30 +00:00
2024-10-02 00:32:48 +00:00
currentCharacter = fetchPlayableCharacter ( ) ;
currentVariation = rememberedVariation ;
2024-09-01 07:22:34 +00:00
styleData = FreeplayStyleRegistry . instance . fetchEntry ( currentCharacter . getFreeplayStyleID ( ) ) ;
2024-07-15 10:30:10 +00:00
rememberedCharacterId = currentCharacter ? . id ? ? Constants . DEFAULT_CHARACTER ;
2024-10-02 00:32:48 +00:00
fromCharSelect = params ? . fromCharSelect ? ? false ;
2024-05-30 09:25:51 +00:00
fromResultsParams = params ? . fromResults ;
2024-10-02 00:32:48 +00:00
prepForNewRank = fromResultsParams ? . playRankAnim ? ? false ;
2024-05-31 09:39:53 +00:00
2024-06-20 20:17:53 +00:00
super ( FlxColor . TRANSPARENT ) ;
2024-10-02 00:32:48 +00:00
if ( stickers ? . members != null ) s t i c k e r S u b S t a t e = s t i c k e r s ;
2023-04-06 05:39:27 +00:00
2024-08-23 12:36:35 +00:00
switch ( currentCharacterId )
{
2024-09-10 21:27:04 +00:00
c ase ( PlayerRegistry . instance . hasNewCharacter ( ) ) => true :
backingCard = new NewCharacterCard ( currentCharacter ) ;
2024-08-23 12:36:35 +00:00
c ase ' b f ' :
2024-08-30 00:12:26 +00:00
backingCard = new BoyfriendCard ( currentCharacter ) ;
2024-08-23 12:36:35 +00:00
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 ( ) ;
2024-08-30 00:04:30 +00:00
fp = new FreeplayScore ( 460 , 60 , 7 , 100 , styleData ) ;
2024-06-20 20:17:53 +00:00
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-09-12 21:44:40 +00:00
charSelectHint = new FlxText ( - 40 , 18 , FlxG . width - 8 - 8 , ' P r e s s [ L O L ] t o c h a n g e c h a r a c t e r s ' , 32 ) ;
2024-06-20 20:17:53 +00:00
2024-08-30 00:04:30 +00:00
bgDad = new FlxSprite ( backingCard . pinkBack . width * 0.74 , 0 ) . loadGraphic ( styleData == null ? ' f r e e p l a y / f r e e p l a y B G d a d ' : styleData . getBgAssetGraphic ( ) ) ;
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 ) ;
2024-09-01 21:56:12 +00:00
funnyCam . filters = [ fadeShaderFilter ] ;
2024-08-23 12:36:35 +00:00
2023-04-06 05:39:27 +00:00
if ( stickerSubState != null )
{
this . persistentUpdate = true ;
this . persistentDraw = true ;
openSubState ( stickerSubState ) ;
stickerSubState . degenStickers ( ) ;
}
2024-08-26 22:01:36 +00:00
#if FEATURE_DISCORD_RPC
2023-01-23 00:55:30 +00:00
// Updating Discord Rich Presence
2024-09-19 14:03:16 +00:00
DiscordClient . instance . setPresence ( { state : ' I n t h e M e n u s ' , details : 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
2024-08-26 22:01:36 +00:00
#if FEATURE_DEBUG_FUNCTIONS
2023-01-23 00:55:30 +00:00
isDebug = true ;
#end
2021-05-06 10:54:57 +00:00
2024-09-01 07:22:34 +00:00
// Block input until the intro finishes.
busy = true ;
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-10-02 00:32:48 +00:00
songs . push ( new FreeplaySongData ( song , level ) ) ;
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-08-30 00:04:30 +00:00
backingCard . instance = this ;
2024-08-23 12:36:35 +00:00
}
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
2024-08-30 00:04:30 +00:00
bgDad . shader = angleMaskShader ;
2023-01-23 00:55:30 +00:00
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
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
} ) ;
2024-10-02 00:32:48 +00:00
for ( diffId in Constants . DEFAULT_DIFFICULTY_LIST_FULL )
2023-10-12 07:20:21 +00:00
{
var diffSprite: DifficultySprite = new DifficultySprite ( diffId ) ;
diffSprite . difficultyId = diffId ;
2024-10-02 00:32:48 +00:00
diffSprite . visible = diffId == Constants . DEFAULT_DIFFICULTY ;
2023-10-12 07:20:21 +00:00
grpDifficulties . add ( diffSprite ) ;
}
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
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
2024-10-02 00:32:48 +00:00
if ( fromCharSelect )
2024-09-01 21:56:12 +00:00
{
2024-08-30 00:04:30 +00:00
blackOverlayBullshitLOLXD . x = 387.76 ;
overhangStuff . y = - 100 ;
backingCard ? . skipIntroTween ( ) ;
2024-09-01 21:56:12 +00:00
}
e lse
{
2024-08-30 00:04:30 +00:00
albumRoll . applyExitMovers ( exitMovers , exitMoversCharSel ) ;
FlxTween . tween ( overhangStuff , { y : - 100 } , 0.3 , { ease : FlxEase . quartOut } ) ;
FlxTween . tween ( blackOverlayBullshitLOLXD , { x : 387.76 } , 0.7 , { ease : FlxEase . quintOut } ) ;
}
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-09-12 21:44:40 +00:00
charSelectHint . alignment = CENTER ;
charSelectHint . font = " 5 b y 7 " ;
charSelectHint . color = 0xFF5F5F5F ;
charSelectHint . text = ' P r e s s [ ${ controls . getDialogueNameFromControl ( FREEPLAY_CHAR_SELECT , true ) } ] t o c h a n g e c h a r a c t e r s ' ;
charSelectHint . y -= 100 ;
FlxTween . tween ( charSelectHint , { y : charSelectHint . y + 100 } , 0.8 , { ease : FlxEase . quartOut } ) ;
exitMovers . set ( [ overhangStuff , fnfFreeplay , ostName , charSelectHint ] ,
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-09-12 21:44:40 +00:00
exitMoversCharSel . set ( [ overhangStuff , fnfFreeplay , ostName , charSelectHint ] ,
2024-08-23 12:36:35 +00:00
{
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
} ) ;
2024-10-02 00:32:48 +00:00
// Reminder, this is a callback function being set, rather than these being called here in create()
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-09-15 01:37:02 +00:00
exitMovers . set ( [ fp , txtCompletion , fnfHighscoreSpr , clearBoxSprite ] ,
2023-03-16 04:17:52 +00:00
{
x : FlxG . width ,
speed : 0.3
} ) ;
2024-09-15 01:37:02 +00:00
exitMoversCharSel . set ( [ fp , txtCompletion , fnfHighscoreSpr , clearBoxSprite ] ,
2024-08-23 12:36:35 +00:00
{
y : - 270 ,
speed : 0.8 ,
wait : 0.1
} ) ;
2024-09-01 21:56:12 +00:00
var diffSelLeft: DifficultySelector = new DifficultySelector ( this , 20 , grpDifficulties . y - 10 , false , controls , styleData ) ;
var diffSelRight: DifficultySelector = new DifficultySelector ( this , 325 , grpDifficulties . y - 10 , true , controls , styleData ) ;
2024-04-24 23:45:17 +00:00
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-10-02 00:32:48 +00:00
if ( PlayerRegistry . instance . hasNewCharacter ( ) )
2024-09-12 21:44:40 +00:00
{
add ( charSelectHint ) ;
}
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 ( ) {
2024-09-01 07:22:34 +00:00
busy = false ;
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 ( ) ;
2024-10-02 00:32:48 +00:00
var daSong = grpCapsules . members [ curSelected ] . freeplayData ;
albumRoll . albumId = daSong ? . data . getAlbumId ( currentDifficulty , currentVariation ) ;
2024-08-28 00:48:56 +00:00
2024-10-02 00:32:48 +00:00
if ( ! fromCharSelect )
2024-09-01 21:56:12 +00:00
{
2024-08-30 00:04:30 +00:00
// render optimisation
if ( _parentState != null ) _parentState . persistentDraw = false ;
FlxTween . color ( bgDad , 0.6 , 0xFF000000 , 0xFFFFFFFF ,
2024-09-01 21:56:12 +00:00
{
ease : FlxEase . expoOut ,
onUpdate : function ( _ ) {
angleMaskShader . extraColor = bgDad . color ;
}
} ) ;
2024-08-30 00:04:30 +00:00
}
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 09:25:51 +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
2024-10-02 00:32:48 +00:00
// Generates song list with the starter params (who our current character is, last remembered difficulty, etc.)
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 ) ;
}
2024-08-30 00:04:30 +00:00
2024-10-02 00:32:48 +00:00
if ( fromCharSelect )
2024-08-30 00:04:30 +00:00
{
enterFromCharSel ( ) ;
onDJIntroDone ( ) ;
}
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
/ * *
2024-10-02 00:32:48 +00:00
* Given the current filter , rebuild the current song list and display it .
* Automatically takes into account currentDifficulty , character , and variation
2024-03-20 18:37:24 +00:00
*
* @ 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-17 02:12:07 +00:00
if ( filterStuff != null ) tempSongs = sortSongs ( tempSongs , filterStuff ) ;
2023-01-23 00:55:30 +00:00
2024-10-02 00:32:48 +00:00
tempSongs = tempSongs . filter ( song - > {
if ( song == null ) return true ; // Random
2024-10-01 16:54:12 +00:00
2024-10-02 00:32:48 +00:00
// Available variations for current character. We get this since bf is usually `default` variation, and `pico` is `pico`
// but sometimes pico can be the default variation (weekend 1 songs), and bf can be `bf` variation (darnell)
var characterVariations: Array < String > = song . data . getVariationsByCharacter ( currentCharacter ) ;
2024-10-01 17:12:10 +00:00
2024-10-02 00:32:48 +00:00
// Gets all available difficulties for our character, via our available variations
var difficultiesAvailable: Array < String > = song . data . listDifficulties ( null , characterVariations ) ;
return difficultiesAvailable . contains ( currentDifficulty ) ;
} ) ;
2024-04-01 22:34:26 +00:00
if ( onlyIfChanged )
{
// == performs equality by reference
if ( tempSongs . isEqualUnordered ( currentFilteredSongs ) ) return ;
}
// Only now do we know that the filter is actually changing.
currentFilter = filterStuff ;
currentFilteredSongs = tempSongs ;
curSelected = 0 ;
2024-10-02 00:32:48 +00:00
// If curSelected is 0, the result will be null and fall back to the rememberedSongId.
// We set this so if we change the filter, we'd remain on the same song if it's still in the list.
rememberedSongId = grpCapsules . members [ curSelected ] ? . freeplayData ? . data . id ? ? rememberedSongId ;
2023-08-28 18:52:03 +00:00
2024-10-02 00:32:48 +00:00
grpCapsules . killMembers ( ) ;
// Initialize the random capsule, with empty/blank info (which we display once bf/pico does his hand)
2023-08-09 06:47:22 +00:00
var randomCapsule: SongMenuItem = grpCapsules . recycle ( SongMenuItem ) ;
2024-08-30 00:04:30 +00:00
randomCapsule . init ( FlxG . width , 0 , null , styleData ) ;
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 ;
2024-10-02 00:32:48 +00:00
randomCapsule . onConfirm = function ( ) {
capsuleOnConfirmRandom ( randomCapsule ) ;
} ;
if ( fromCharSelect ) randomCapsule . forcePosition ( ) ;
2024-08-30 00:04:30 +00:00
e lse
2024-10-02 00:32:48 +00:00
randomCapsule . initJumpIn ( 0 , force ) ;
var hsvShader: HSVShader = new HSVShader ( ) ;
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-08-30 00:04:30 +00:00
funnyMenu . init ( FlxG . width , 0 , tempSong , styleData ) ;
2023-09-29 00:29:19 +00:00
funnyMenu . onConfirm = function ( ) {
2024-07-22 22:38:22 +00:00
capsuleOnOpenDefault ( funnyMenu ) ;
2023-09-29 00:29:19 +00:00
} ;
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-08-28 18:52:03 +00:00
funnyMenu . hsvShader = hsvShader ;
2024-05-30 03:34:00 +00:00
funnyMenu . newText . animation . curAnim . curFrame = 45 - ( ( i * 4 ) % 45 ) ;
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-10-02 00:32:48 +00:00
refreshCapsuleDisplays ( ) ;
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 {
2024-10-02 00:32:48 +00:00
return SortUtil . alphabetically ( a ? . data . songName ? ? ' ' , b ? . d a t a . 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 ' ) ;
2024-10-02 00:32:48 +00:00
songsToFilter = songsToFilter . filter ( filteredSong - > {
if ( filteredSong == null ) return true ; // Random
return filterRegexp . match ( filteredSong . data . songName ) ;
2024-04-17 02:12:07 +00:00
} ) ;
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"
2024-10-02 00:32:48 +00:00
songsToFilter = songsToFilter . filter ( filteredSong - > {
if ( filteredSong == null ) return true ; // Random
return filteredSong . data . songName . toLowerCase ( ) . startsWith ( songFilter . filterData ? ? ' ' ) ;
2024-04-17 02:12:07 +00:00
} ) ;
c ase ALL :
2024-08-26 22:01:36 +00:00
// no filter!
2024-04-17 02:12:07 +00:00
c ase FAVORITE :
2024-10-02 00:32:48 +00:00
songsToFilter = songsToFilter . filter ( filteredSong - > {
if ( filteredSong == null ) return true ; // Random
return filteredSong . isFav ;
2024-04-17 02:12:07 +00:00
} ) ;
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-08-28 10:08:30 +00:00
if ( fromResultsParams ? . newRank == SHIT )
{
if ( dj != null ) dj . fistPumpLossIntro ( ) ;
}
e lse
{
if ( dj != null ) dj . fistPumpIntro ( ) ;
}
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-10-01 17:12:10 +00:00
function rankAnimSlam ( fromResultsParams : Null < FromResultsParams > ) : Void
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-08-28 10:08:30 +00:00
if ( dj != null ) dj . fistPumpLoss ( ) ;
2024-05-30 03:34:00 +00:00
}
e lse
{
2024-08-28 10:08:30 +00:00
if ( dj != null ) dj . fistPump ( ) ;
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-09-01 07:22:34 +00:00
function tryOpenCharSelect ( ) : Void
{
// Check if we have ACCESS to character select!
trace ( ' I s P i c o u n l o c k e d ? ${ PlayerRegistry . instance . fetchEntry ( ' p i c o ' ) ? . isUnlocked ( ) } ' ) ;
trace ( ' N u m b e r o f c h a r a c t e r s : ${ PlayerRegistry . instance . countUnlockedCharacters ( ) } ' ) ;
if ( PlayerRegistry . instance . countUnlockedCharacters ( ) > 1 )
{
trace ( ' O p e n i n g c h a r a c t e r s e l e c t ! ' ) ;
}
e lse
{
trace ( ' N o t e n o u g h c h a r a c t e r s u n l o c k e d t o o p e n c h a r a c t e r s e l e c t ! ' ) ;
FunkinSound . playOnce ( Paths . sound ( ' c a n c e l M e n u ' ) ) ;
return ;
}
busy = true ;
FunkinSound . playOnce ( Paths . sound ( ' c o n f i r m M e n u ' ) ) ;
if ( dj != null )
{
dj . toCharSelect ( ) ;
}
// Get this character's transition delay, with a reasonable default.
var transitionDelay: Float = currentCharacter . getFreeplayDJData ( ) ? . getCharSelectTransitionDelay ( ) ? ? 0.25 ;
new FlxTimer ( ) . start ( transitionDelay , _ - > {
transitionToCharSelect ( ) ;
} ) ;
}
function transitionToCharSelect ( ) : 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 ) ;
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 } ) ;
2024-10-02 00:32:48 +00:00
FlxG . sound . music ? . fadeOut ( 0.9 , 0 ) ;
2024-09-01 07:22:34 +00:00
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 moveDataY = funnyMoveShit . y ? ? spr . y ;
var moveDataSpeed = funnyMoveShit . speed ? ? 0.2 ;
var moveDataWait = funnyMoveShit . wait ? ? 0.0 ;
FlxTween . tween ( spr , { y : moveDataY + spr . y } , moveDataSpeed , { ease : FlxEase . backIn } ) ;
}
}
backingCard ? . enterCharSel ( ) ;
}
function enterFromCharSel ( ) : Void
{
busy = true ;
if ( _parentState != null ) _parentState . persistentDraw = false ;
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 : 1.5 ,
wait : 0.1
} ) ;
add ( transitionGradient ) ;
// FlxTween.tween(transitionGradient, {alpha: 0}, 1, {ease: FlxEase.circIn});
// 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 ( 0.0 , 1.0 , 0.8 , { ease : FlxEase . quadIn } ) ;
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 moveDataY = funnyMoveShit . y ? ? spr . y ;
var moveDataSpeed = funnyMoveShit . speed ? ? 0.2 ;
var moveDataWait = funnyMoveShit . wait ? ? 0.0 ;
spr . y += moveDataY ;
FlxTween . tween ( spr , { y : spr . y - moveDataY } , moveDataSpeed * 1.2 ,
{
ease : FlxEase . expoOut ,
onComplete : function ( _ ) {
for ( index => capsule in grpCapsules . members )
{
capsule . doLerp = true ;
fromCharSelect = false ;
busy = false ;
albumRoll . applyExitMovers ( exitMovers , exitMoversCharSel ) ;
}
}
} ) ;
}
}
}
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 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 .
* /
2024-08-28 10:05:28 +00:00
public 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-09-12 21:44:40 +00:00
var hintTimer: Float = 0 ;
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-09-12 21:44:40 +00:00
if ( charSelectHint != null )
{
hintTimer += elapsed * 2 ;
var targetAmt: Float = ( Math . sin ( hintTimer ) + 1 ) / 2 ;
charSelectHint . alpha = FlxMath . lerp ( 0.3 , 0.9 , targetAmt ) ;
}
2024-08-26 22:01:36 +00:00
#if FEATURE_DEBUG_FUNCTIONS
2024-06-18 21:56:24 +00:00
if ( FlxG . keys . justPressed . P )
{
2024-09-15 01:37:02 +00:00
FlxG . switchState ( ( ) - > FreeplayState . build (
2024-06-18 21:56:24 +00:00
{
{
2024-09-01 21:56:12 +00:00
character : currentCharacterId == " p i c o " ? Constants . DEFAULT_CHARACTER : " p i c o " ,
2024-06-18 21:56:24 +00:00
}
} ) ) ;
2024-05-30 03:34:00 +00:00
}
if ( FlxG . keys . justPressed . T )
{
2024-06-20 20:17:53 +00:00
rankAnimStart ( fromResultsParams ? ?
{
playRankAnim : true ,
newRank : PERFECT_GOLD ,
songId : " t u t o r i a l " ,
difficultyId : " h a r d "
} ) ;
2024-05-30 03:34:00 +00:00
}
2024-06-01 23:25:52 +00:00
// if (FlxG.keys.justPressed.H)
// {
// rankDisplayNew(fromResultsParams);
// }
// if (FlxG.keys.justPressed.G)
// {
// rankAnimSlam(fromResultsParams);
// }
2024-09-01 21:56:12 +00:00
#end // ^<-- FEATURE_DEBUG_FUNCTIONS
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
{
2024-09-01 07:22:34 +00:00
tryOpenCharSelect ( ) ;
2024-07-08 20:22:38 +00:00
}
2024-06-09 06:22:03 +00:00
if ( controls . FREEPLAY_FAVORITE && ! busy )
2023-01-23 00:55:30 +00:00
{
2024-10-02 00:32:48 +00:00
var targetSong = grpCapsules . members [ curSelected ] ? . freeplayData ;
2024-04-01 22:34:26 +00:00
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 ) ;
2024-08-28 10:05:28 +00:00
if ( dj != null ) FlxG . watch . addQuick ( ' d j - a n i m ' , dj . getCurrentAnimation ( ) ) ;
2023-10-17 04:38:28 +00:00
}
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-08-28 10:05:28 +00:00
if ( controls . BACK && ! busy )
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 ,
2024-10-02 05:57:25 +00:00
restartTrack : false ,
// Continue playing this music between states, until a different music track gets played.
persist : true
2024-04-03 05:40:08 +00:00
} ) ;
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
}
}
2024-08-30 00:04:30 +00:00
override function beatHit ( ) : Bool
{
backingCard ? . beatHit ( ) ;
return super . beatHit ( ) ;
}
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-05-14 00:30:36 +00:00
FlxG . cameras . remove ( funnyCam ) ;
2023-01-23 00:55:30 +00:00
}
2024-10-02 00:32:48 +00:00
/ * *
* changeDiff is the root of both difficulty and variation changes / management .
* It will check the difficulty of the current variation , all available variations , and all available difficulties per variation .
* It ' s g e n e r a l l y r e c o m m e n d e d t h a t a f t e r c a l l i n g t h i s y o u r e - s o r t t h e s o n g l i s t , h o w e v e r u s u a l l y i t ' s already on the way to being sorted .
* @ param change
* @ param force
* /
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-10-02 00:32:48 +00:00
// Available variations for current character. We get this since bf is usually `default` variation, and `pico` is `pico`
// but sometimes pico can be the default variation (weekend 1 songs), and bf can be `bf` variation (darnell)
var characterVariations: Array < String > = grpCapsules . members [ curSelected ] . freeplayData ? . data . getVariationsByCharacter ( currentCharacter ) ? ? Constants . DEFAULT_VARIATION_LIST ;
2023-01-23 00:55:30 +00:00
2024-10-02 00:32:48 +00:00
// Gets all available difficulties for our character, via our available variations
var difficultiesAvailable: Array < String > = grpCapsules . members [ curSelected ] . freeplayData ? . data . listDifficulties ( null ,
characterVariations ) ? ? Constants . DEFAULT_DIFFICULTY_LIST ;
2023-01-23 00:55:30 +00:00
2024-10-02 00:32:48 +00:00
var currentDifficultyIndex: Int = difficultiesAvailable . indexOf ( currentDifficulty ) ;
if ( currentDifficultyIndex == - 1 ) currentDifficultyIndex = difficultiesAvailable . indexOf ( Constants . DEFAULT_DIFFICULTY ) ;
2023-10-12 07:20:21 +00:00
2024-10-02 00:32:48 +00:00
currentDifficultyIndex += change ;
2023-10-12 07:20:21 +00:00
2024-10-02 00:32:48 +00:00
if ( currentDifficultyIndex < 0 ) currentDifficultyIndex = Std . int ( difficultiesAvailable . length - 1 ) ;
if ( currentDifficultyIndex >= difficultiesAvailable . length ) currentDifficultyIndex = 0 ;
2024-10-01 17:12:10 +00:00
2024-10-02 00:32:48 +00:00
// Update the current difficulty
currentDifficulty = difficultiesAvailable [ currentDifficultyIndex ] ;
for ( variation in characterVariations )
2024-10-01 17:12:10 +00:00
{
2024-10-02 00:32:48 +00:00
if ( grpCapsules . members [ curSelected ] . freeplayData ? . data . hasDifficulty ( currentDifficulty , variation ) ? ? false )
{
currentVariation = variation ;
rememberedVariation = variation ;
break ;
}
2024-10-01 17:12:10 +00:00
}
2024-10-02 00:32:48 +00:00
var daSong: Null < FreeplaySongData > = grpCapsules . members [ curSelected ] . freeplayData ;
2023-10-11 03:32:01 +00:00
if ( daSong != null )
{
2024-10-02 00:32:48 +00:00
var targetSong: Null < Song > = SongRegistry . instance . fetchEntry ( daSong . data . id ) ;
2024-06-11 04:40:43 +00:00
if ( targetSong == null )
{
2024-10-02 00:32:48 +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 . data . id } ) ' ) ;
2024-06-11 04:40:43 +00:00
return ;
}
2024-10-03 00:38:47 +00:00
var songScore: Null < SaveScoreData > = Save . instance . getSongScore ( daSong . data . id , currentDifficulty , currentVariation ) ;
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 ) ;
2024-10-02 00:32:48 +00:00
rememberedDifficulty = currentDifficulty ;
grpCapsules . members [ curSelected ] . refreshDisplay ( ) ;
2023-10-11 03:32:01 +00:00
}
e lse
{
intendedScore = 0 ;
intendedCompletion = 0.0 ;
2024-10-02 00:32:48 +00:00
rememberedDifficulty = currentDifficulty ;
2023-10-11 03:32:01 +00:00
}
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
for ( diffSprite in grpDifficulties . group . members )
{
if ( diffSprite == null ) continue ;
2024-10-02 00:32:48 +00:00
diffSprite . visible = false ;
if ( diffSprite . difficultyId == currentDifficulty )
2023-10-12 07:20:21 +00:00
{
2024-10-02 00:32:48 +00:00
diffSprite . visible = true ;
2023-10-12 07:20:21 +00:00
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 ( ) ;
} ) ;
}
}
}
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 ;
2024-10-02 00:32:48 +00:00
if ( songCapsule . freeplayData != null )
2024-01-11 05:30:00 +00:00
{
2024-10-02 00:32:48 +00:00
songCapsule . init ( null , null , songCapsule . freeplayData ) ;
2024-06-05 22:21:57 +00:00
songCapsule . checkClip ( ) ;
2024-01-11 05:30:00 +00:00
}
}
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-10-02 00:32:48 +00:00
var newAlbumId: Null < String > = daSong ? . data . getAlbumId ( currentDifficulty , currentVariation ) ;
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.
2024-10-02 00:32:48 +00:00
albumRoll . setDifficultyStars ( daSong ? . data . getDifficulty ( currentDifficulty , currentVariation ) ? . difficultyRating ? ? 0 ) ;
2023-01-23 00:55:30 +00:00
}
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.
2024-10-02 00:32:48 +00:00
return cap . alive && cap . freeplayData != null ;
2023-10-17 00:12:40 +00:00
} ) ;
trace ( ' A v a i l a b l e s o n g s : ${ availableSongCapsules . map ( function ( cap ) {
2024-10-02 00:32:48 +00:00
return cap ? . freeplayData ? . data . 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
}
2024-07-22 22:38:22 +00:00
/ * *
* Called when hitting ENTER to open the instrumental list .
* /
function capsuleOnOpenDefault ( cap : SongMenuItem ) : Void
{
2024-10-02 00:32:48 +00:00
var targetSongId: String = cap ? . freeplayData ? . data . id ? ? ' u n k n o w n ' ;
2024-07-22 22:38:22 +00:00
var targetSongNullable: Null < Song > = SongRegistry . instance . fetchEntry ( targetSongId ) ;
if ( targetSongNullable == null )
{
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 } ) ' ) ;
return ;
}
var targetSong: Song = targetSongNullable ;
2024-10-02 00:32:48 +00:00
var targetDifficultyId: String = currentDifficulty ;
2024-09-27 18:26:08 +00:00
var targetVariation: Null < String > = currentVariation ;
trace ( ' t a r g e t s o n g : ${ targetSongId } ( ${ targetVariation } ) ' ) ;
2024-10-02 00:32:48 +00:00
var targetLevelId: Null < String > = cap ? . freeplayData ? . levelId ;
2024-07-22 22:38:22 +00:00
PlayStatePlaylist . campaignId = targetLevelId ? ? null ;
var targetDifficulty: Null < SongDifficulty > = targetSong . getDifficulty ( targetDifficultyId , targetVariation ) ;
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 ;
}
trace ( ' t a r g e t d i f f i c u l t y : ${ targetDifficultyId } ' ) ;
trace ( ' t a r g e t v a r i a t i o n : ${ targetDifficulty ? . variation ? ? Constants . DEFAULT_VARIATION } ' ) ;
var baseInstrumentalId: String = targetSong . getBaseInstrumentalId ( targetDifficultyId , targetDifficulty ? . variation ? ? Constants . DEFAULT_VARIATION ) ? ? ' ' ;
var altInstrumentalIds: Array < String > = targetSong . listAltInstrumentalIds ( targetDifficultyId ,
targetDifficulty ? . variation ? ? Constants . DEFAULT_VARIATION ) ? ? [ ] ;
if ( altInstrumentalIds . length > 0 )
{
var instrumentalIds = [ baseInstrumentalId ] . concat ( altInstrumentalIds ) ;
openInstrumentalList ( cap , instrumentalIds ) ;
}
e lse
{
trace ( ' N O A L T S ' ) ;
capsuleOnConfirmDefault ( cap ) ;
}
}
public function getControls ( ) : Controls
{
return controls ;
}
function openInstrumentalList ( cap : SongMenuItem , instrumentalIds : Array < String > ) : Void
{
busy = true ;
capsuleOptionsMenu = new CapsuleOptionsMenu ( this , cap . x + 175 , cap . y + 115 , instrumentalIds ) ;
capsuleOptionsMenu . cameras = [ funnyCam ] ;
capsuleOptionsMenu . zIndex = 10000 ;
add ( capsuleOptionsMenu ) ;
capsuleOptionsMenu . onConfirm = function ( targetInstId : String ) {
capsuleOnConfirmDefault ( cap , targetInstId ) ;
} ;
}
var capsuleOptionsMenu: Null < CapsuleOptionsMenu > = null ;
public function cleanupCapsuleOptionsMenu ( ) : Void
{
this . busy = false ;
if ( capsuleOptionsMenu != null )
{
remove ( capsuleOptionsMenu ) ;
capsuleOptionsMenu = null ;
}
}
/ * *
* Called when hitting ENTER to play the song .
* /
function capsuleOnConfirmDefault ( cap : SongMenuItem , ? targetInstId : String ) : 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-10-02 00:32:48 +00:00
var targetSongId: String = cap ? . freeplayData ? . data . id ? ? ' u n k n o w n ' ;
2024-06-20 20:17:53 +00:00
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-09-27 18:26:08 +00:00
var targetVariation: Null < String > = currentVariation ;
2024-10-02 00:32:48 +00:00
var targetLevelId: Null < String > = cap ? . freeplayData ? . levelId ;
2024-06-20 20:17:53 +00:00
PlayStatePlaylist . campaignId = targetLevelId ? ? null ;
2023-08-06 20:24:34 +00:00
2024-10-02 00:32:48 +00:00
var targetDifficulty: Null < SongDifficulty > = targetSong . getDifficulty ( currentDifficulty , currentVariation ) ;
2024-06-07 01:38:00 +00:00
if ( targetDifficulty == null )
{
2024-10-02 00:32:48 +00:00
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 ( ${ currentDifficulty } ) ' ) ;
2024-06-07 01:38:00 +00:00
return ;
}
2024-09-10 05:33:15 +00:00
if ( targetInstId == null )
{
2024-10-02 00:32:48 +00:00
var baseInstrumentalId: String = targetSong ? . getBaseInstrumentalId ( currentDifficulty , targetDifficulty . variation ? ? Constants . DEFAULT_VARIATION ) ? ? ' ' ;
2024-09-10 05:33:15 +00:00
targetInstId = baseInstrumentalId ;
}
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
2024-08-30 00:04:30 +00:00
new FlxTimer ( ) . start ( styleData ? . getStartDelay ( ) , f u n c t i o n ( t m r : FlxTimer ) {
2024-06-05 19:02:29 +00:00
FunkinSound . emptyPartialQueue ( ) ;
2024-10-02 00:32:48 +00:00
Paths . setCurrentLevel ( cap ? . freeplayData ? . levelId ) ;
2024-02-17 04:48:43 +00:00
LoadingState . loadPlayState (
2023-08-06 20:24:34 +00:00
{
targetSong : targetSong ,
2024-10-02 00:32:48 +00:00
targetDifficulty : currentDifficulty ,
targetVariation : currentVariation ,
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
2024-08-26 22:01:36 +00:00
#if FEATURE_DEBUG_FUNCTIONS
2024-04-01 22:34:26 +00:00
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
} ) ;
}
2024-10-02 00:32:48 +00:00
function refreshCapsuleDisplays ( ) : Void
{
grpCapsules . forEachAlive ( ( cap : SongMenuItem ) - > {
cap . refreshDisplay ( ) ;
} ) ;
}
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 ;
2024-10-02 00:32:48 +00:00
return song . data . id == rememberedSongId ;
2023-10-12 07:20:21 +00:00
} ) ;
2024-04-01 22:34:26 +00:00
if ( curSelected == - 1 ) curSelected = 0 ;
2023-10-12 07:20:21 +00:00
}
if ( rememberedDifficulty != null )
{
2024-10-02 00:32:48 +00:00
currentDifficulty = rememberedDifficulty ;
}
if ( rememberedVariation != null )
{
currentVariation = rememberedVariation ;
2023-10-12 07:20:21 +00:00
}
}
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 ] ;
2024-10-02 00:32:48 +00:00
if ( daSongCapsule . freeplayData != null )
2023-08-09 07:03:58 +00:00
{
2024-10-03 00:38:47 +00:00
var songScore: Null < SaveScoreData > = Save . instance . getSongScore ( daSongCapsule . freeplayData . data . id , currentDifficulty , currentVariation ) ;
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 ) ;
2024-10-02 00:32:48 +00:00
rememberedSongId = daSongCapsule . freeplayData . data . id ;
2023-10-12 07:20:21 +00:00
changeDiff ( ) ;
2024-10-02 00:32:48 +00:00
daSongCapsule . refreshDisplay ( ) ;
2023-08-09 07:03:58 +00:00
}
e lse
{
intendedScore = 0 ;
2023-10-11 03:32:01 +00:00
intendedCompletion = 0.0 ;
2023-10-12 07:20:21 +00:00
rememberedSongId = null ;
2024-07-15 10:30:10 +00:00
rememberedDifficulty = Constants . DEFAULT_DIFFICULTY ;
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-10-02 00:32:48 +00:00
var previewSong: Null < Song > = daSongCapsule ? . freeplayData ? . data ;
2024-09-27 18:26:08 +00:00
if ( previewSong == null ) return ;
2024-10-01 17:12:10 +00:00
// Check if character-specific difficulty exists
2024-10-02 00:32:48 +00:00
var songDifficulty: Null < SongDifficulty > = previewSong . getDifficulty ( currentDifficulty , currentVariation ) ;
2024-10-01 17:12:10 +00:00
2024-10-02 00:32:48 +00:00
var baseInstrumentalId: String = previewSong . getBaseInstrumentalId ( currentDifficulty , songDifficulty ? . variation ? ? Constants . DEFAULT_VARIATION ) ? ? ' ' ;
var altInstrumentalIds: Array < String > = previewSong . listAltInstrumentalIds ( currentDifficulty ,
2024-07-22 22:38:22 +00:00
songDifficulty ? . variation ? ? Constants . DEFAULT_VARIATION ) ? ? [ ] ;
2024-06-18 21:56:24 +00:00
var instSuffix: String = baseInstrumentalId ;
2024-08-26 22:01:36 +00:00
#if FEATURE_DEBUG_FUNCTIONS
2024-06-18 21:56:24 +00:00
if ( altInstrumentalIds . length > 0 && FlxG . keys . pressed . CONTROL )
{
instSuffix = altInstrumentalIds [ 0 ] ;
}
#end
2024-06-10 16:42:27 +00:00
instSuffix = ( instSuffix != ' ' ) ? ' - $ instSuffix ' : ' ' ;
2024-10-02 00:32:48 +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 : ${ previewSong . id } : ${ instSuffix } ' ) ;
FunkinSound . playMusic ( previewSong . id ,
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 ,
2024-08-30 00:04:30 +00:00
start : 0 ,
end : 0.2
2024-06-06 00:49:33 +00:00
} ,
onLoad : function ( ) {
FlxG . sound . music . fadeIn ( 2 , 0 , 0.4 ) ;
}
} ) ;
2024-09-01 21:56:12 +00:00
if ( songDifficulty != null )
{
2024-08-30 00:04:30 +00:00
Conductor . instance . mapTimeChanges ( songDifficulty . timeChanges ) ;
Conductor . instance . update ( FlxG . sound ? . music ? . time ? ? 0.0 ) ;
}
2024-06-06 00:49:33 +00:00
}
}
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-08-29 17:22:56 +00:00
result = new MainMenuState ( true ) ;
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
2024-08-28 10:05:28 +00:00
var parent: FreeplayState ;
2024-09-01 21:56:12 +00:00
public function n e w ( parent : FreeplayState , x : Float , y : Float , flipped : Bool , controls : Controls , ? styleData : FreeplayStyle = null )
2023-01-23 00:55:30 +00:00
{
super ( x , y ) ;
2021-12-08 00:29:26 +00:00
2024-08-28 10:05:28 +00:00
this . parent = parent ;
2023-01-23 00:55:30 +00:00
this . controls = controls ;
2021-12-08 00:29:26 +00:00
2024-08-30 00:04:30 +00:00
frames = Paths . getSparrowAtlas ( styleData == null ? ' f r e e p l a y / f r e e p l a y S e l e c t o r ' : styleData . getSelectorAssetKey ( ) ) ;
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-08-28 10:05:28 +00:00
if ( flipX && controls . UI_RIGHT_P && ! parent . busy ) moveShitDown ( ) ;
if ( ! flipX && controls . UI_LEFT_P && ! parent . busy ) 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
/ * *
2024-10-02 00:32:48 +00:00
* We used to have a billion fields , but this SongMetadata variable should be all we need
* to be able to get most information about an available song .
* For example , you can get the artist via ` data . songArtist `
*
* You can usually get various other particulars of a specific difficulty / variation by
* u sing data . getDifficulty ( ) , and inputting specifics on your difficulty , variations , etc .
* See the getters here for s o n g C h a r a c t e r , f u l l S o n g N a m e , a n d s o n g S t a r t i n g B p m f o r e x a m p l e s .
*
* @ see Song
2024-03-20 18:37:24 +00:00
* /
2024-10-02 00:32:48 +00:00
public var data: Song ;
2023-10-12 07:20:21 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* The level id of the song , useful for s o r t i n g f r o m w e e k 1 - > w e e k 7 + w e e k e n d 1
* and for p r o p e r l y l o a d i n g P l a y S t a t e P l a y l i s t f o r p r e l o a d i n g o n w e b
* /
public var levelId( get , never ) : Null < String > ;
2024-06-06 00:49:33 +00:00
2024-10-02 00:32:48 +00:00
function get_levelId ( ) : Null < String >
{
return _levelId ;
}
2024-01-11 05:30:00 +00:00
2024-10-02 00:32:48 +00:00
var _levelId: String ;
2024-01-11 05:30:00 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* Whether or not the song has been favorited .
* /
public var isFav: Bool = false ;
2023-01-23 00:55:30 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* Whether the player has seen / played this song before within freeplay
* /
2024-10-03 00:38:47 +00:00
public var isNew( get , never ) : Bool ;
2024-01-11 05:30:00 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* The d efault opponent for t h e s o n g .
* Does the getter stuff for y o u d e p e n d i n g o n y o u r c u r r e n t ( or r a t h e r , r e m e m b e r d ) variation and difficulty .
* /
public var songCharacter( get , never ) : String ;
2024-05-11 05:05:51 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* The full song name , dynamically generated depending on your current ( or r a t h e r , rememberd ) variation and difficulty .
* /
public var fullSongName( get , never ) : String ;
2024-05-30 09:25:51 +00:00
2024-10-02 00:32:48 +00:00
/ * *
* The starting BPM of the song , dynamically generated depending on your current ( or r a t h e r , rememberd ) variation and difficulty .
* /
public var songStartingBpm( get , never ) : Float ;
2024-01-11 05:30:00 +00:00
2024-10-02 00:32:48 +00:00
public var difficultyRating( get , never ) : Int ;
2024-06-08 22:29:55 +00:00
2024-10-02 00:32:48 +00:00
public var scoringRank( get , never ) : Null < ScoringRank > ;
2024-01-11 05:30:00 +00:00
2024-10-02 00:32:48 +00:00
public function n e w ( data : Song , levelData : Level )
2023-01-23 00:55:30 +00:00
{
2024-10-02 00:32:48 +00:00
this . data = data ;
_levelId = levelData . id ;
this . isFav = Save . instance . isSongFavorited ( data . songName ) ;
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 )
{
2024-10-02 00:32:48 +00:00
Save . instance . favoriteSong ( data . songName ) ;
2024-05-21 06:49:07 +00:00
}
e lse
{
2024-10-02 00:32:48 +00:00
Save . instance . unfavoriteSong ( data . songName ) ;
2024-05-21 06:49:07 +00:00
}
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-10-02 00:32:48 +00:00
// this.isNew = song.isSongNew(suffixedDifficulty);
}
2024-10-01 16:54:12 +00:00
2024-10-03 00:38:47 +00:00
function get_isNew ( ) : Bool
{
// We use a slightly different manner to get the new status of a song than the other getters here
// `isSongNew()` only takes a single variation, and it's data that isn't accessible via the Song data/metadata
// it's stored in the song .hxc script in a function that overrides `isSongNew()`
// and is only accessible with the correct valid variation inputs
var variations: Array < String > = data . getVariationsByCharacterId ( FreeplayState . rememberedCharacterId ) ;
var variation: String = data . getFirstValidVariation ( FreeplayState . rememberedDifficulty , null , variations ) ;
return data . isSongNew ( FreeplayState . rememberedDifficulty , variation ) ;
}
2024-10-02 00:32:48 +00:00
function get_songCharacter ( ) : String
{
var variations: Array < String > = data . getVariationsByCharacterId ( FreeplayState . rememberedCharacterId ) ;
return data . getDifficulty ( FreeplayState . rememberedDifficulty , null , variations ) ? . characters . opponent ? ? ' ' ;
}
2024-10-01 16:54:12 +00:00
2024-10-02 00:32:48 +00:00
function get_fullSongName ( ) : String
{
var variations: Array < String > = data . getVariationsByCharacterId ( FreeplayState . rememberedCharacterId ) ;
2024-01-11 05:30:00 +00:00
2024-10-02 00:32:48 +00:00
return data . getDifficulty ( FreeplayState . rememberedDifficulty , null , variations ) ? . songName ? ? data . songName ;
}
2024-09-27 18:26:08 +00:00
2024-10-02 00:32:48 +00:00
function get_songStartingBpm ( ) : Float
{
var variations: Array < String > = data . getVariationsByCharacterId ( FreeplayState . rememberedCharacterId ) ;
2024-05-30 09:25:51 +00:00
2024-10-02 00:32:48 +00:00
return data . getDifficulty ( FreeplayState . rememberedDifficulty , null , variations ) ? . getStartingBPM ( ) ? ? 0 ;
}
2024-05-30 09:25:51 +00:00
2024-10-02 00:32:48 +00:00
function get_difficultyRating ( ) : Int
{
var variations: Array < String > = data . getVariationsByCharacterId ( FreeplayState . rememberedCharacterId ) ;
return data . getDifficulty ( FreeplayState . rememberedDifficulty , null , variations ) ? . difficultyRating ? ? 0 ;
}
2024-06-06 00:49:33 +00:00
2024-10-02 00:32:48 +00:00
function get_scoringRank ( ) : Null < ScoringRank >
{
2024-10-03 00:38:47 +00:00
var variations: Array < String > = data . getVariationsByCharacterId ( FreeplayState . rememberedCharacterId ) ;
var variation: String = data . getFirstValidVariation ( FreeplayState . rememberedDifficulty , null , variations ) ;
return Save . instance . getSongRank ( data . id , FreeplayState . rememberedDifficulty , variation ) ;
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-10-02 00:32:48 +00:00
/ * *
* Parameters used to initialize the FreeplayState .
* /
typedef FreeplayStateParams =
{
? character : String ,
? fromCharSelect : Bool ,
? 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 ;
/ * *
* Whether or not to play the rank animation on returning to freeplay .
* /
var playRankAnim: Bool ;
/ * *
* 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-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 ( ) ;
2024-09-10 21:30:33 +00:00
if ( assetDiffIdParts . length == 0 )
{
trace ( ' C o u l d n o t f i n d d i f f i c u l t y a s s e t : f r e e p l a y / f r e e p l a y ${ diffId } ( f r o m ${ diffId } ) ' ) ;
return ;
} ;
2024-07-28 05:42:09 +00:00
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 ) ) ;
2024-09-10 21:30:33 +00:00
trace ( ' L o a d e d d i f f i c u l t y a s s e t : f r e e p l a y / f r e e p l a y ${ assetDiffId } ( f r o m ${ diffId } ) ' ) ;
2023-11-20 16:12:50 +00:00
}
2023-10-12 07:20:21 +00:00
}
}