mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-11-25 21:55:55 +00:00
Merge branch 'feature/char-unlock' of https://github.com/FunkinCrew/Funkin-secret into feature/char-unlock
This commit is contained in:
commit
a901677853
18
CHANGELOG.md
18
CHANGELOG.md
|
|
@ -4,14 +4,28 @@ All notable changes will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [0.5.0] - 2024-08-??
|
## [0.5.0] - 2024-09-12
|
||||||
### Added
|
### Added
|
||||||
- Added a new Character Select screen to switch between playable characters in Freeplay
|
- Added a new Character Select screen to switch between playable characters in Freeplay
|
||||||
- Modding isn't 100% there but we're working on it!
|
- Modding isn't 100% there but we're working on it!
|
||||||
- Added Pico as a playable character! Unlock him by completing Weekend 1 (if you haven't already done that)
|
- Added Pico as a playable character! Unlock him by completing Weekend 1 (if you haven't already done that)
|
||||||
- The songs from Weekend 1 have moved; you must now switch to Pico in Freeplay to access them
|
- The songs from Weekend 1 have moved; you must now switch to Pico in Freeplay to access them
|
||||||
- Added ## new Pico remixes! Access them by selecting Pico from in the Character Select screen
|
- Added 10 new Pico remixes! Access them by selecting Pico from in the Character Select screen
|
||||||
|
- Bopeebo (Pico Mix)
|
||||||
|
- Fresh (Pico Mix)
|
||||||
|
- DadBattle (Pico Mix)
|
||||||
|
- Spookeez (Pico Mix)
|
||||||
|
- South (Pico Mix)
|
||||||
|
- Philly Nice (Pico Mix)
|
||||||
|
- Blammed (Pico Mix)
|
||||||
|
- Eggnog (Pico Mix)
|
||||||
|
- Ugh (Pico Mix)
|
||||||
|
- Guns (Pico Mix)
|
||||||
|
- Added 1 new Boyfriend remix! Access it by selecting Pico from in the Character Select screen
|
||||||
|
- Darnell (BF Mix)
|
||||||
- Added 2 new Erect remixes! Access them by switching difficulty on the song
|
- Added 2 new Erect remixes! Access them by switching difficulty on the song
|
||||||
|
- Cocoa Erect
|
||||||
|
- Ugh Erect
|
||||||
- Implemented support for a new Instrumental Selector in Freeplay
|
- Implemented support for a new Instrumental Selector in Freeplay
|
||||||
- Beating a Pico remix lets you use that instrumental when playing as Boyfriend
|
- Beating a Pico remix lets you use that instrumental when playing as Boyfriend
|
||||||
- Added the first batch of Erect Stages! These graphical overhauls of the original stages will be used when playing Erect remixes and Pico remixes
|
- Added the first batch of Erect Stages! These graphical overhauls of the original stages will be used when playing Erect remixes and Pico remixes
|
||||||
|
|
|
||||||
38
source/funkin/Assets.hx
Normal file
38
source/funkin/Assets.hx
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package funkin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around `openfl.utils.Assets` which disallows access to the harmful functions.
|
||||||
|
* Later we'll add Funkin-specific caching to this.
|
||||||
|
*/
|
||||||
|
class Assets
|
||||||
|
{
|
||||||
|
public static function getText(path:String):String
|
||||||
|
{
|
||||||
|
return openfl.utils.Assets.getText(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getMusic(path:String):openfl.media.Sound
|
||||||
|
{
|
||||||
|
return openfl.utils.Assets.getMusic(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getBitmapData(path:String):openfl.display.BitmapData
|
||||||
|
{
|
||||||
|
return openfl.utils.Assets.getBitmapData(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getBytes(path:String):haxe.io.Bytes
|
||||||
|
{
|
||||||
|
return openfl.utils.Assets.getBytes(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function exists(path:String, ?type:openfl.utils.AssetType):Bool
|
||||||
|
{
|
||||||
|
return openfl.utils.Assets.exists(path, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function list(type:openfl.utils.AssetType):Array<String>
|
||||||
|
{
|
||||||
|
return openfl.utils.Assets.list(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ import funkin.play.PlayStatePlaylist;
|
||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
import funkin.data.story.level.LevelRegistry;
|
import funkin.data.story.level.LevelRegistry;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
|
import funkin.data.freeplay.style.FreeplayStyleRegistry;
|
||||||
import funkin.data.event.SongEventRegistry;
|
import funkin.data.event.SongEventRegistry;
|
||||||
import funkin.data.stage.StageRegistry;
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||||
|
|
@ -170,6 +171,7 @@ class InitState extends FlxState
|
||||||
ConversationRegistry.instance.loadEntries();
|
ConversationRegistry.instance.loadEntries();
|
||||||
DialogueBoxRegistry.instance.loadEntries();
|
DialogueBoxRegistry.instance.loadEntries();
|
||||||
SpeakerRegistry.instance.loadEntries();
|
SpeakerRegistry.instance.loadEntries();
|
||||||
|
FreeplayStyleRegistry.instance.loadEntries();
|
||||||
AlbumRegistry.instance.loadEntries();
|
AlbumRegistry.instance.loadEntries();
|
||||||
StageRegistry.instance.loadEntries();
|
StageRegistry.instance.loadEntries();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,9 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
|
||||||
var animFrame:Int = Math.round(levels[i].value * 5);
|
var animFrame:Int = Math.round(levels[i].value * 5);
|
||||||
|
|
||||||
#if desktop
|
#if desktop
|
||||||
animFrame = Math.round(animFrame * FlxG.sound.volume);
|
// Web version scales with the Flixel volume level.
|
||||||
|
// This line brings platform parity but looks worse.
|
||||||
|
// animFrame = Math.round(animFrame * FlxG.sound.volume);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
animFrame = Math.floor(Math.min(5, animFrame));
|
animFrame = Math.floor(Math.min(5, animFrame));
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,13 @@ class PlayerData
|
||||||
@:default(false)
|
@:default(false)
|
||||||
public var showUnownedChars:Bool = false;
|
public var showUnownedChars:Bool = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which freeplay style to use for this character.
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default("bf")
|
||||||
|
public var freeplayStyle:String = Constants.DEFAULT_FREEPLAY_STYLE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data for displaying this character in the Freeplay menu.
|
* Data for displaying this character in the Freeplay menu.
|
||||||
* If null, display no DJ.
|
* If null, display no DJ.
|
||||||
|
|
@ -105,6 +112,9 @@ class PlayerFreeplayDJData
|
||||||
@:jignored
|
@:jignored
|
||||||
var prefixToOffsetsMap:Map<String, Array<Float>>;
|
var prefixToOffsetsMap:Map<String, Array<Float>>;
|
||||||
|
|
||||||
|
@:optional
|
||||||
|
var charSelect:Null<PlayerFreeplayDJCharSelectData>;
|
||||||
|
|
||||||
@:optional
|
@:optional
|
||||||
var cartoon:Null<PlayerFreeplayDJCartoonData>;
|
var cartoon:Null<PlayerFreeplayDJCartoonData>;
|
||||||
|
|
||||||
|
|
@ -237,6 +247,11 @@ class PlayerFreeplayDJData
|
||||||
{
|
{
|
||||||
return fistPump?.loopBadEndFrame ?? 0;
|
return fistPump?.loopBadEndFrame ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCharSelectTransitionDelay():Float
|
||||||
|
{
|
||||||
|
return charSelect?.transitionDelay ?? 0.25;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlayerCharSelectData
|
class PlayerCharSelectData
|
||||||
|
|
@ -253,6 +268,8 @@ class PlayerCharSelectData
|
||||||
|
|
||||||
typedef PlayerResultsData =
|
typedef PlayerResultsData =
|
||||||
{
|
{
|
||||||
|
var music:PlayerResultsMusicData;
|
||||||
|
|
||||||
var perfect:Array<PlayerResultsAnimationData>;
|
var perfect:Array<PlayerResultsAnimationData>;
|
||||||
var excellent:Array<PlayerResultsAnimationData>;
|
var excellent:Array<PlayerResultsAnimationData>;
|
||||||
var great:Array<PlayerResultsAnimationData>;
|
var great:Array<PlayerResultsAnimationData>;
|
||||||
|
|
@ -260,6 +277,27 @@ typedef PlayerResultsData =
|
||||||
var loss:Array<PlayerResultsAnimationData>;
|
var loss:Array<PlayerResultsAnimationData>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef PlayerResultsMusicData =
|
||||||
|
{
|
||||||
|
@:optional
|
||||||
|
var PERFECT_GOLD:String;
|
||||||
|
|
||||||
|
@:optional
|
||||||
|
var PERFECT:String;
|
||||||
|
|
||||||
|
@:optional
|
||||||
|
var EXCELLENT:String;
|
||||||
|
|
||||||
|
@:optional
|
||||||
|
var GREAT:String;
|
||||||
|
|
||||||
|
@:optional
|
||||||
|
var GOOD:String;
|
||||||
|
|
||||||
|
@:optional
|
||||||
|
var SHIT:String;
|
||||||
|
}
|
||||||
|
|
||||||
typedef PlayerResultsAnimationData =
|
typedef PlayerResultsAnimationData =
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
@ -300,6 +338,11 @@ typedef PlayerResultsAnimationData =
|
||||||
var loopFrameLabel:Null<String>;
|
var loopFrameLabel:Null<String>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef PlayerFreeplayDJCharSelectData =
|
||||||
|
{
|
||||||
|
var transitionDelay:Float;
|
||||||
|
}
|
||||||
|
|
||||||
typedef PlayerFreeplayDJCartoonData =
|
typedef PlayerFreeplayDJCartoonData =
|
||||||
{
|
{
|
||||||
var soundClickFrame:Int;
|
var soundClickFrame:Int;
|
||||||
|
|
|
||||||
9
source/funkin/data/freeplay/style/CHANGELOG.md
Normal file
9
source/funkin/data/freeplay/style/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Freeplay Style Data Schema Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial release.
|
||||||
48
source/funkin/data/freeplay/style/FreeplayStyleData.hx
Normal file
48
source/funkin/data/freeplay/style/FreeplayStyleData.hx
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
package funkin.data.freeplay.style;
|
||||||
|
|
||||||
|
import funkin.data.animation.AnimationData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type definition for the data for an album of songs.
|
||||||
|
* It includes things like what graphics to display in Freeplay.
|
||||||
|
* @see https://lib.haxe.org/p/json2object/
|
||||||
|
*/
|
||||||
|
typedef FreeplayStyleData =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Semantic version for style data.
|
||||||
|
*/
|
||||||
|
public var version:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asset key for the background image.
|
||||||
|
*/
|
||||||
|
public var bgAsset:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asset key for the difficulty selector image.
|
||||||
|
*/
|
||||||
|
public var selectorAsset:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asset key for the numbers shown at the top right of the screen.
|
||||||
|
*/
|
||||||
|
public var numbersAsset:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asset key for the freeplay capsules.
|
||||||
|
*/
|
||||||
|
public var capsuleAsset:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color data for the capsule text outline.
|
||||||
|
* the order of this array goes as follows: [DESELECTED, SELECTED]
|
||||||
|
*/
|
||||||
|
public var capsuleTextColors:Array<String>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay time after confirming a song selection, before entering PlayState.
|
||||||
|
* Useful for letting longer animations play out.
|
||||||
|
*/
|
||||||
|
public var startDelay:Float;
|
||||||
|
}
|
||||||
84
source/funkin/data/freeplay/style/FreeplayStyleRegistry.hx
Normal file
84
source/funkin/data/freeplay/style/FreeplayStyleRegistry.hx
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
package funkin.data.freeplay.style;
|
||||||
|
|
||||||
|
import funkin.ui.freeplay.FreeplayStyle;
|
||||||
|
import funkin.data.freeplay.style.FreeplayStyleData;
|
||||||
|
import funkin.ui.freeplay.ScriptedFreeplayStyle;
|
||||||
|
|
||||||
|
class FreeplayStyleRegistry extends BaseRegistry<FreeplayStyle, FreeplayStyleData>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The current version string for the style data format.
|
||||||
|
* Handle breaking changes by incrementing this value
|
||||||
|
* and adding migration to the `migrateStyleData()` function.
|
||||||
|
*/
|
||||||
|
public static final FREEPLAYSTYLE_DATA_VERSION:thx.semver.Version = '1.0.0';
|
||||||
|
|
||||||
|
public static final FREEPLAYSTYLE_DATA_VERSION_RULE:thx.semver.VersionRule = '1.0.x';
|
||||||
|
|
||||||
|
public static final instance:FreeplayStyleRegistry = new FreeplayStyleRegistry();
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super('FREEPLAYSTYLE', 'ui/freeplay/styles', FREEPLAYSTYLE_DATA_VERSION_RULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read, parse, and validate the JSON data and produce the corresponding data object.
|
||||||
|
* @param id The ID of the entry to load.
|
||||||
|
* @return The parsed data object.
|
||||||
|
*/
|
||||||
|
public function parseEntryData(id:String):Null<FreeplayStyleData>
|
||||||
|
{
|
||||||
|
// JsonParser does not take type parameters,
|
||||||
|
// otherwise this function would be in BaseRegistry.
|
||||||
|
var parser:json2object.JsonParser<FreeplayStyleData> = new json2object.JsonParser<FreeplayStyleData>();
|
||||||
|
parser.ignoreUnknownVariables = false;
|
||||||
|
|
||||||
|
switch (loadEntryFile(id))
|
||||||
|
{
|
||||||
|
case {fileName: fileName, contents: contents}:
|
||||||
|
parser.fromJson(contents, fileName);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser.errors.length > 0)
|
||||||
|
{
|
||||||
|
printErrors(parser.errors, id);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parser.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse and validate the JSON data and produce the corresponding data object.
|
||||||
|
*
|
||||||
|
* NOTE: Must be implemented on the implementation class.
|
||||||
|
* @param contents The JSON as a string.
|
||||||
|
* @param fileName An optional file name for error reporting.
|
||||||
|
* @return The parsed data object.
|
||||||
|
*/
|
||||||
|
public function parseEntryDataRaw(contents:String, ?fileName:String):Null<FreeplayStyleData>
|
||||||
|
{
|
||||||
|
var parser:json2object.JsonParser<FreeplayStyleData> = new json2object.JsonParser<FreeplayStyleData>();
|
||||||
|
parser.ignoreUnknownVariables = false;
|
||||||
|
parser.fromJson(contents, fileName);
|
||||||
|
|
||||||
|
if (parser.errors.length > 0)
|
||||||
|
{
|
||||||
|
printErrors(parser.errors, fileName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parser.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createScriptedEntry(clsName:String):FreeplayStyle
|
||||||
|
{
|
||||||
|
return ScriptedFreeplayStyle.init(clsName, 'unknown');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScriptedClassNames():Array<String>
|
||||||
|
{
|
||||||
|
return ScriptedFreeplayStyle.listScriptClasses();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- If the value isn't present, it will use the `playData.characters.opponent`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the opponent)
|
- If the value isn't present, it will use the `playData.characters.opponent`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the opponent)
|
||||||
- Added `playData.characters.playerVocals` to specify which vocal track(s) to play for the player.
|
- Added `playData.characters.playerVocals` to specify which vocal track(s) to play for the player.
|
||||||
- If the value isn't present, it will use the `playData.characters.player`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the player)
|
- If the value isn't present, it will use the `playData.characters.player`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the player)
|
||||||
|
- Added `offsets.altVocals` field to apply vocal offsets when alternate instrumentals are used.
|
||||||
|
|
||||||
|
|
||||||
## [2.2.3]
|
## [2.2.3]
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -257,18 +257,27 @@ class SongOffsets implements ICloneable<SongOffsets>
|
||||||
public var altInstrumentals:Map<String, Float>;
|
public var altInstrumentals:Map<String, Float>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The offset, in milliseconds, to apply to the song's vocals, relative to the chart.
|
* The offset, in milliseconds, to apply to the song's vocals, relative to the song's base instrumental.
|
||||||
* These are applied ON TOP OF the instrumental offset.
|
* These are applied ON TOP OF the instrumental offset.
|
||||||
*/
|
*/
|
||||||
@:optional
|
@:optional
|
||||||
@:default([])
|
@:default([])
|
||||||
public var vocals:Map<String, Float>;
|
public var vocals:Map<String, Float>;
|
||||||
|
|
||||||
public function new(instrumental:Float = 0.0, ?altInstrumentals:Map<String, Float>, ?vocals:Map<String, Float>)
|
/**
|
||||||
|
* The offset, in milliseconds, to apply to the songs vocals, relative to each alternate instrumental.
|
||||||
|
* This is useful for the circumstance where, for example, an alt instrumental has a few seconds of lead in before the song starts.
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default([])
|
||||||
|
public var altVocals:Map<String, Map<String, Float>>;
|
||||||
|
|
||||||
|
public function new(instrumental:Float = 0.0, ?altInstrumentals:Map<String, Float>, ?vocals:Map<String, Float>, ?altVocals:Map<String, Map<String, Float>>)
|
||||||
{
|
{
|
||||||
this.instrumental = instrumental;
|
this.instrumental = instrumental;
|
||||||
this.altInstrumentals = altInstrumentals == null ? new Map<String, Float>() : altInstrumentals;
|
this.altInstrumentals = altInstrumentals == null ? new Map<String, Float>() : altInstrumentals;
|
||||||
this.vocals = vocals == null ? new Map<String, Float>() : vocals;
|
this.vocals = vocals == null ? new Map<String, Float>() : vocals;
|
||||||
|
this.altVocals = altVocals == null ? new Map<String, Map<String, Float>>() : altVocals;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInstrumentalOffset(?instrumental:String):Float
|
public function getInstrumentalOffset(?instrumental:String):Float
|
||||||
|
|
@ -293,11 +302,19 @@ class SongOffsets implements ICloneable<SongOffsets>
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVocalOffset(charId:String):Float
|
public function getVocalOffset(charId:String, ?instrumental:String):Float
|
||||||
{
|
{
|
||||||
if (!this.vocals.exists(charId)) return 0.0;
|
if (instrumental == null)
|
||||||
|
{
|
||||||
return this.vocals.get(charId);
|
if (!this.vocals.exists(charId)) return 0.0;
|
||||||
|
return this.vocals.get(charId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this.altVocals.exists(instrumental)) return 0.0;
|
||||||
|
if (!this.altVocals.get(instrumental).exists(charId)) return 0.0;
|
||||||
|
return this.altVocals.get(instrumental).get(charId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setVocalOffset(charId:String, value:Float):Float
|
public function setVocalOffset(charId:String, value:Float):Float
|
||||||
|
|
@ -320,7 +337,7 @@ class SongOffsets implements ICloneable<SongOffsets>
|
||||||
*/
|
*/
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'SongOffsets(${this.instrumental}ms, ${this.altInstrumentals}, ${this.vocals})';
|
return 'SongOffsets(${this.instrumental}ms, ${this.altInstrumentals}, ${this.vocals}, ${this.altVocals})';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
* Handle breaking changes by incrementing this value
|
* Handle breaking changes by incrementing this value
|
||||||
* and adding migration to the `migrateStageData()` function.
|
* and adding migration to the `migrateStageData()` function.
|
||||||
*/
|
*/
|
||||||
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.3";
|
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.4";
|
||||||
|
|
||||||
public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.2.x";
|
public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.2.x";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class StageRegistry extends BaseRegistry<Stage, StageData>
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"mainStage", "mainStageErect", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "limoRideErect", "mallXmas", "mallEvil", "school",
|
"mainStage", "mainStageErect", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "limoRideErect", "mallXmas", "mallEvil", "school",
|
||||||
"schoolEvil", "tankmanBattlefield", "phillyStreets", "phillyBlazin",
|
"schoolEvil", "tankmanBattlefield", "phillyStreets", "phillyStreetsErect", "phillyBlazin",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,12 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
throw 'Null path specified for FlxAtlasSprite!';
|
throw 'Null path specified for FlxAtlasSprite!';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate asset path.
|
||||||
|
if (!Assets.exists('${path}/Animation.json'))
|
||||||
|
{
|
||||||
|
throw 'FlxAtlasSprite does not have an Animation.json file at the specified path (${path})';
|
||||||
|
}
|
||||||
|
|
||||||
super(x, y, path, settings);
|
super(x, y, path, settings);
|
||||||
|
|
||||||
if (this.anim.stageInstance == null)
|
if (this.anim.stageInstance == null)
|
||||||
|
|
@ -105,23 +111,6 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
return this.currentAnimation;
|
return this.currentAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* `anim.finished` always returns false on looping animations,
|
|
||||||
* but this function will return true if we are on the last frame of the looping animation.
|
|
||||||
*/
|
|
||||||
public function isLoopFinished():Bool
|
|
||||||
{
|
|
||||||
if (this.anim == null) return false;
|
|
||||||
if (!this.anim.isPlaying) return false;
|
|
||||||
|
|
||||||
// Reverse animation finished.
|
|
||||||
if (this.anim.reversed && this.anim.curFrame == 0) return true;
|
|
||||||
// Forward animation finished.
|
|
||||||
if (!this.anim.reversed && this.anim.curFrame >= (this.anim.length - 1)) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var _completeAnim:Bool = false;
|
var _completeAnim:Bool = false;
|
||||||
|
|
||||||
var fr:FlxKeyFrame = null;
|
var fr:FlxKeyFrame = null;
|
||||||
|
|
@ -142,6 +131,8 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
// Skip if not allowed to play animations.
|
// Skip if not allowed to play animations.
|
||||||
if ((!canPlayOtherAnims && !ignoreOther)) return;
|
if ((!canPlayOtherAnims && !ignoreOther)) return;
|
||||||
|
|
||||||
|
if (anim == null) return;
|
||||||
|
|
||||||
if (id == null || id == '') id = this.currentAnimation;
|
if (id == null || id == '') id = this.currentAnimation;
|
||||||
|
|
||||||
if (this.currentAnimation == id && !restart)
|
if (this.currentAnimation == id && !restart)
|
||||||
|
|
@ -189,10 +180,16 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
// Move to the first frame of the animation.
|
// Move to the first frame of the animation.
|
||||||
// goToFrameLabel(id);
|
// goToFrameLabel(id);
|
||||||
trace('Playing animation $id');
|
trace('Playing animation $id');
|
||||||
this.anim.play(id, restart, false, startFrame);
|
if (this.anim.symbolDictionary.exists(id) || (this.anim.getByName(id) != null))
|
||||||
goToFrameLabel(id);
|
{
|
||||||
|
this.anim.play(id, restart, false, startFrame);
|
||||||
fr = anim.getFrameLabel(id);
|
}
|
||||||
|
// Only call goToFrameLabel if there is a frame label with that name. This prevents annoying warnings!
|
||||||
|
if (getFrameLabelNames().indexOf(id) != -1)
|
||||||
|
{
|
||||||
|
goToFrameLabel(id);
|
||||||
|
fr = anim.getFrameLabel(id);
|
||||||
|
}
|
||||||
|
|
||||||
anim.curFrame += startFrame;
|
anim.curFrame += startFrame;
|
||||||
this.currentAnimation = id;
|
this.currentAnimation = id;
|
||||||
|
|
@ -218,6 +215,8 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
*/
|
*/
|
||||||
public function isLoopComplete():Bool
|
public function isLoopComplete():Bool
|
||||||
{
|
{
|
||||||
|
if (this.anim == null) return false;
|
||||||
|
if (!this.anim.isPlaying) return false;
|
||||||
return (anim.reversed && anim.curFrame == 0 || !(anim.reversed) && (anim.curFrame) >= (anim.length - 1));
|
return (anim.reversed && anim.curFrame == 0 || !(anim.reversed) && (anim.curFrame) >= (anim.length - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,6 +243,18 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
this.anim.goToFrameLabel(label);
|
this.anim.goToFrameLabel(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFrameLabelNames(?layer:haxe.extern.EitherType<Int, String> = null)
|
||||||
|
{
|
||||||
|
var labels = this.anim.getFrameLabels(layer);
|
||||||
|
var array = [];
|
||||||
|
for (label in labels)
|
||||||
|
{
|
||||||
|
array.push(label.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
function getNextFrameLabel(label:String):String
|
function getNextFrameLabel(label:String):String
|
||||||
{
|
{
|
||||||
return listAnimations()[(getLabelIndex(label) + 1) % listAnimations().length];
|
return listAnimations()[(getLabelIndex(label) + 1) % listAnimations().length];
|
||||||
|
|
@ -272,7 +283,7 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
{
|
{
|
||||||
onAnimationFrame.dispatch(currentAnimation, frame);
|
onAnimationFrame.dispatch(currentAnimation, frame);
|
||||||
|
|
||||||
if (fr != null && frame > (fr.index + fr.duration - 1) || isLoopFinished())
|
if (fr != null && frame > (fr.index + fr.duration - 1) || isLoopComplete())
|
||||||
{
|
{
|
||||||
anim.pause();
|
anim.pause();
|
||||||
_onAnimationComplete();
|
_onAnimationComplete();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,25 @@
|
||||||
package funkin.graphics.shaders;
|
package funkin.graphics.shaders;
|
||||||
|
|
||||||
import flixel.system.FlxAssets.FlxShader;
|
import flixel.system.FlxAssets.FlxShader;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
|
||||||
class AngleMask extends FlxShader
|
class AngleMask extends FlxShader
|
||||||
{
|
{
|
||||||
|
public var extraColor(default, set):FlxColor = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
function set_extraColor(value:FlxColor):FlxColor
|
||||||
|
{
|
||||||
|
extraTint.value = [value.redFloat, value.greenFloat, value.blueFloat];
|
||||||
|
this.extraColor = value;
|
||||||
|
|
||||||
|
return this.extraColor;
|
||||||
|
}
|
||||||
|
|
||||||
@:glFragmentSource('
|
@:glFragmentSource('
|
||||||
#pragma header
|
#pragma header
|
||||||
|
|
||||||
|
uniform vec3 extraTint;
|
||||||
|
|
||||||
uniform vec2 endPosition;
|
uniform vec2 endPosition;
|
||||||
vec2 hash22(vec2 p) {
|
vec2 hash22(vec2 p) {
|
||||||
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
|
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
|
||||||
|
|
@ -69,6 +82,7 @@ class AngleMask extends FlxShader
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 col = antialias(openfl_TextureCoordv);
|
vec4 col = antialias(openfl_TextureCoordv);
|
||||||
|
col.xyz = col.xyz * extraTint.xyz;
|
||||||
// col.xyz = gamma(col.xyz);
|
// col.xyz = gamma(col.xyz);
|
||||||
gl_FragColor = col;
|
gl_FragColor = col;
|
||||||
}')
|
}')
|
||||||
|
|
@ -77,5 +91,6 @@ class AngleMask extends FlxShader
|
||||||
super();
|
super();
|
||||||
|
|
||||||
endPosition.value = [90, 100]; // 100 AS DEFAULT WORKS NICELY FOR FREEPLAY?
|
endPosition.value = [90, 100]; // 100 AS DEFAULT WORKS NICELY FOR FREEPLAY?
|
||||||
|
extraTint.value = [1, 1, 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
51
source/funkin/graphics/shaders/BlueFade.hx
Normal file
51
source/funkin/graphics/shaders/BlueFade.hx
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
package funkin.graphics.shaders;
|
||||||
|
|
||||||
|
import flixel.system.FlxAssets.FlxShader;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
|
||||||
|
class BlueFade extends FlxShader
|
||||||
|
{
|
||||||
|
public var fadeVal(default, set):Float;
|
||||||
|
|
||||||
|
function set_fadeVal(val:Float):Float
|
||||||
|
{
|
||||||
|
fadeAmt.value = [val];
|
||||||
|
fadeVal = val;
|
||||||
|
// trace(fadeVal);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fade(startAmt:Float = 0, targetAmt:Float = 1, duration:Float, _options:TweenOptions):Void
|
||||||
|
{
|
||||||
|
fadeVal = startAmt;
|
||||||
|
FlxTween.tween(this, {fadeVal: targetAmt}, duration, _options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:glFragmentSource('
|
||||||
|
#pragma header
|
||||||
|
|
||||||
|
// Value from (0, 1)
|
||||||
|
uniform float fadeAmt;
|
||||||
|
|
||||||
|
// fade the image to blue as it fades to black
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 tex = flixel_texture2D(bitmap, openfl_TextureCoordv);
|
||||||
|
|
||||||
|
vec4 finalColor = mix(vec4(vec4(0.0, 0.0, tex.b, tex.a) * fadeAmt), vec4(tex * fadeAmt), fadeAmt);
|
||||||
|
|
||||||
|
// Output to screen
|
||||||
|
gl_FragColor = finalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
')
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.fadeVal = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import flixel.system.FlxAssets.FlxShader;
|
||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
import openfl.display.ShaderParameter;
|
import openfl.display.ShaderParameter;
|
||||||
import openfl.display.ShaderParameterType;
|
import openfl.display.ShaderParameterType;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
import openfl.utils.Assets;
|
import openfl.utils.Assets;
|
||||||
|
|
||||||
typedef Light =
|
typedef Light =
|
||||||
|
|
@ -94,6 +95,14 @@ class RuntimeRainShader extends RuntimePostEffectShader
|
||||||
return mask = value;
|
return mask = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var rainColor(default, set):FlxColor;
|
||||||
|
|
||||||
|
function set_rainColor(color:FlxColor):FlxColor
|
||||||
|
{
|
||||||
|
this.setFloatArray("uRainColor", [color.red / 255, color.green / 255, color.blue / 255]);
|
||||||
|
return rainColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
public var lightMap(default, set):BitmapData;
|
public var lightMap(default, set):BitmapData;
|
||||||
|
|
||||||
function set_lightMap(value:BitmapData):BitmapData
|
function set_lightMap(value:BitmapData):BitmapData
|
||||||
|
|
@ -113,6 +122,7 @@ class RuntimeRainShader extends RuntimePostEffectShader
|
||||||
public function new()
|
public function new()
|
||||||
{
|
{
|
||||||
super(Assets.getText(Paths.frag('rain')));
|
super(Assets.getText(Paths.frag('rain')));
|
||||||
|
this.rainColor = 0xFF6680cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(elapsed:Float):Void
|
public function update(elapsed:Float):Void
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,22 @@ interface INoteScriptedClass extends IScriptedClass
|
||||||
public function onNoteMiss(event:NoteScriptEvent):Void;
|
public function onNoteMiss(event:NoteScriptEvent):Void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a set of callbacks available to scripted classes which represent sprites synced with the BPM.
|
||||||
|
*/
|
||||||
|
interface IBPMSyncedScriptedClass extends IScriptedClass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called once every step of the song.
|
||||||
|
*/
|
||||||
|
public function onStepHit(event:SongTimeScriptEvent):Void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once every beat of the song.
|
||||||
|
*/
|
||||||
|
public function onBeatHit(event:SongTimeScriptEvent):Void;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Developer note:
|
* Developer note:
|
||||||
*
|
*
|
||||||
|
|
@ -86,7 +102,7 @@ interface INoteScriptedClass extends IScriptedClass
|
||||||
/**
|
/**
|
||||||
* Defines a set of callbacks available to scripted classes that involve the lifecycle of the Play State.
|
* Defines a set of callbacks available to scripted classes that involve the lifecycle of the Play State.
|
||||||
*/
|
*/
|
||||||
interface IPlayStateScriptedClass extends INoteScriptedClass
|
interface IPlayStateScriptedClass extends INoteScriptedClass extends IBPMSyncedScriptedClass
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Called when the game is paused.
|
* Called when the game is paused.
|
||||||
|
|
@ -136,16 +152,6 @@ interface IPlayStateScriptedClass extends INoteScriptedClass
|
||||||
*/
|
*/
|
||||||
public function onSongEvent(event:SongEventScriptEvent):Void;
|
public function onSongEvent(event:SongEventScriptEvent):Void;
|
||||||
|
|
||||||
/**
|
|
||||||
* Called once every step of the song.
|
|
||||||
*/
|
|
||||||
public function onStepHit(event:SongTimeScriptEvent):Void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called once every beat of the song.
|
|
||||||
*/
|
|
||||||
public function onBeatHit(event:SongTimeScriptEvent):Void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the countdown of the song starts.
|
* Called when the countdown of the song starts.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,10 @@ class PolymodHandler
|
||||||
|
|
||||||
Polymod.addImportAlias('funkin.data.event.SongEventSchema', funkin.data.event.SongEventSchema.SongEventSchemaRaw);
|
Polymod.addImportAlias('funkin.data.event.SongEventSchema', funkin.data.event.SongEventSchema.SongEventSchemaRaw);
|
||||||
|
|
||||||
|
// `lime.utils.Assets` literally just has a private `resolveClass` function for some reason? so we replace it with our own.
|
||||||
|
Polymod.addImportAlias('lime.utils.Assets', funkin.Assets);
|
||||||
|
Polymod.addImportAlias('openfl.utils.Assets', funkin.Assets);
|
||||||
|
|
||||||
// Add blacklisting for prohibited classes and packages.
|
// Add blacklisting for prohibited classes and packages.
|
||||||
|
|
||||||
// `Sys`
|
// `Sys`
|
||||||
|
|
@ -269,11 +273,6 @@ class PolymodHandler
|
||||||
// System.load() can load malicious DLLs
|
// System.load() can load malicious DLLs
|
||||||
Polymod.blacklistImport('lime.system.System');
|
Polymod.blacklistImport('lime.system.System');
|
||||||
|
|
||||||
// `lime.utils.Assets`
|
|
||||||
// Literally just has a private `resolveClass` function for some reason?
|
|
||||||
Polymod.blacklistImport('lime.utils.Assets');
|
|
||||||
Polymod.blacklistImport('openfl.utils.Assets');
|
|
||||||
|
|
||||||
// `openfl.desktop.NativeProcess`
|
// `openfl.desktop.NativeProcess`
|
||||||
// Can load native processes on the host operating system.
|
// Can load native processes on the host operating system.
|
||||||
Polymod.blacklistImport('openfl.desktop.NativeProcess');
|
Polymod.blacklistImport('openfl.desktop.NativeProcess');
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,21 @@ class ScriptEventDispatcher
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Std.isOfType(target, IBPMSyncedScriptedClass))
|
||||||
|
{
|
||||||
|
var t:IBPMSyncedScriptedClass = cast(target, IBPMSyncedScriptedClass);
|
||||||
|
switch (event.type)
|
||||||
|
{
|
||||||
|
case SONG_BEAT_HIT:
|
||||||
|
t.onBeatHit(cast event);
|
||||||
|
return;
|
||||||
|
case SONG_STEP_HIT:
|
||||||
|
t.onStepHit(cast event);
|
||||||
|
return;
|
||||||
|
default: // Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Std.isOfType(target, IPlayStateScriptedClass))
|
if (Std.isOfType(target, IPlayStateScriptedClass))
|
||||||
{
|
{
|
||||||
var t:IPlayStateScriptedClass = cast(target, IPlayStateScriptedClass);
|
var t:IPlayStateScriptedClass = cast(target, IPlayStateScriptedClass);
|
||||||
|
|
@ -102,12 +117,6 @@ class ScriptEventDispatcher
|
||||||
case NOTE_GHOST_MISS:
|
case NOTE_GHOST_MISS:
|
||||||
t.onNoteGhostMiss(cast event);
|
t.onNoteGhostMiss(cast event);
|
||||||
return;
|
return;
|
||||||
case SONG_BEAT_HIT:
|
|
||||||
t.onBeatHit(cast event);
|
|
||||||
return;
|
|
||||||
case SONG_STEP_HIT:
|
|
||||||
t.onStepHit(cast event);
|
|
||||||
return;
|
|
||||||
case SONG_START:
|
case SONG_START:
|
||||||
t.onSongStart(event);
|
t.onSongStart(event);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -668,7 +668,7 @@ class PlayState extends MusicBeatSubState
|
||||||
// Prepare the current song's instrumental and vocals to be played.
|
// Prepare the current song's instrumental and vocals to be played.
|
||||||
if (!overrideMusic && currentChart != null)
|
if (!overrideMusic && currentChart != null)
|
||||||
{
|
{
|
||||||
currentChart.cacheInst();
|
currentChart.cacheInst(currentInstrumental);
|
||||||
currentChart.cacheVocals();
|
currentChart.cacheVocals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,7 +677,7 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
if (currentChart.offsets != null)
|
if (currentChart.offsets != null)
|
||||||
{
|
{
|
||||||
Conductor.instance.instrumentalOffset = currentChart.offsets.getInstrumentalOffset();
|
Conductor.instance.instrumentalOffset = currentChart.offsets.getInstrumentalOffset(currentInstrumental);
|
||||||
}
|
}
|
||||||
|
|
||||||
Conductor.instance.mapTimeChanges(currentChart.timeChanges);
|
Conductor.instance.mapTimeChanges(currentChart.timeChanges);
|
||||||
|
|
@ -860,7 +860,7 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
// Stop the vocals if they already exist.
|
// Stop the vocals if they already exist.
|
||||||
if (vocals != null) vocals.stop();
|
if (vocals != null) vocals.stop();
|
||||||
vocals = currentChart.buildVocals();
|
vocals = currentChart.buildVocals(currentInstrumental);
|
||||||
|
|
||||||
if (vocals.members.length == 0)
|
if (vocals.members.length == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -1791,7 +1791,7 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
// Stop the vocals if they already exist.
|
// Stop the vocals if they already exist.
|
||||||
if (vocals != null) vocals.stop();
|
if (vocals != null) vocals.stop();
|
||||||
vocals = currentChart.buildVocals();
|
vocals = currentChart.buildVocals(currentInstrumental);
|
||||||
|
|
||||||
if (vocals.members.length == 0)
|
if (vocals.members.length == 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -404,12 +404,12 @@ class ResultState extends MusicBeatSubState
|
||||||
// }
|
// }
|
||||||
|
|
||||||
new FlxTimer().start(rank.getMusicDelay(), _ -> {
|
new FlxTimer().start(rank.getMusicDelay(), _ -> {
|
||||||
if (rank.hasMusicIntro())
|
var introMusic:String = Paths.music(getMusicPath(playerCharacter, rank) + '/' + getMusicPath(playerCharacter, rank) + '-intro');
|
||||||
|
if (Assets.exists(introMusic))
|
||||||
{
|
{
|
||||||
// Play the intro music.
|
// Play the intro music.
|
||||||
var introMusic:String = Paths.music(rank.getMusicPath() + '/' + rank.getMusicPath() + '-intro');
|
|
||||||
FunkinSound.load(introMusic, 1.0, false, true, true, () -> {
|
FunkinSound.load(introMusic, 1.0, false, true, true, () -> {
|
||||||
FunkinSound.playMusic(rank.getMusicPath(),
|
FunkinSound.playMusic(getMusicPath(playerCharacter, rank),
|
||||||
{
|
{
|
||||||
startingVolume: 1.0,
|
startingVolume: 1.0,
|
||||||
overrideExisting: true,
|
overrideExisting: true,
|
||||||
|
|
@ -420,7 +420,7 @@ class ResultState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FunkinSound.playMusic(rank.getMusicPath(),
|
FunkinSound.playMusic(getMusicPath(playerCharacter, rank),
|
||||||
{
|
{
|
||||||
startingVolume: 1.0,
|
startingVolume: 1.0,
|
||||||
overrideExisting: true,
|
overrideExisting: true,
|
||||||
|
|
@ -441,6 +441,11 @@ class ResultState extends MusicBeatSubState
|
||||||
super.create();
|
super.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMusicPath(playerCharacter:Null<PlayableCharacter>, rank:ScoringRank):String
|
||||||
|
{
|
||||||
|
return playerCharacter?.getResultsMusicPath(rank) ?? 'resultsNORMAL';
|
||||||
|
}
|
||||||
|
|
||||||
var rankTallyTimer:Null<FlxTimer> = null;
|
var rankTallyTimer:Null<FlxTimer> = null;
|
||||||
var clearPercentTarget:Int = 100;
|
var clearPercentTarget:Int = 100;
|
||||||
var clearPercentLerp:Int = 0;
|
var clearPercentLerp:Int = 0;
|
||||||
|
|
|
||||||
|
|
@ -122,14 +122,18 @@ class AnimateAtlasCharacter extends BaseCharacter
|
||||||
*/
|
*/
|
||||||
public override function isAnimationFinished():Bool
|
public override function isAnimationFinished():Bool
|
||||||
{
|
{
|
||||||
return mainSprite.isAnimationFinished();
|
return mainSprite?.isAnimationFinished() ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadAtlasSprite():FlxAtlasSprite
|
function loadAtlasSprite():FlxAtlasSprite
|
||||||
{
|
{
|
||||||
trace('[ATLASCHAR] Loading sprite atlas for ${characterId}.');
|
trace('[ATLASCHAR] Loading sprite atlas for ${characterId}.');
|
||||||
|
|
||||||
var sprite:FlxAtlasSprite = new FlxAtlasSprite(0, 0, Paths.animateAtlas(_data.assetPath));
|
var animLibrary:String = Paths.getLibrary(_data.assetPath);
|
||||||
|
var animPath:String = Paths.stripLibrary(_data.assetPath);
|
||||||
|
var assetPath:String = Paths.animateAtlas(animPath, animLibrary);
|
||||||
|
|
||||||
|
var sprite:FlxAtlasSprite = new FlxAtlasSprite(0, 0, assetPath);
|
||||||
|
|
||||||
// sprite.onAnimationComplete.removeAll();
|
// sprite.onAnimationComplete.removeAll();
|
||||||
sprite.onAnimationComplete.add(this.onAnimationFinished);
|
sprite.onAnimationComplete.add(this.onAnimationFinished);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ class PopUpStuff extends FlxTypedGroup<FunkinSprite>
|
||||||
*/
|
*/
|
||||||
var noteStyle:NoteStyle;
|
var noteStyle:NoteStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offsets that are applied to all elements, independent of the note style.
|
||||||
|
* Used to allow scripts to reposition the elements.
|
||||||
|
*/
|
||||||
|
var offsets:Array<Int> = [0, 0];
|
||||||
|
|
||||||
override public function new(noteStyle:NoteStyle)
|
override public function new(noteStyle:NoteStyle)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
|
@ -42,9 +48,11 @@ class PopUpStuff extends FlxTypedGroup<FunkinSprite>
|
||||||
rating.y = (FlxG.camera.height * 0.45 - 60);
|
rating.y = (FlxG.camera.height * 0.45 - 60);
|
||||||
rating.y -= rating.height / 2;
|
rating.y -= rating.height / 2;
|
||||||
|
|
||||||
var offsets = noteStyle.getJudgementSpriteOffsets(daRating);
|
|
||||||
rating.x += offsets[0];
|
rating.x += offsets[0];
|
||||||
rating.y += offsets[1];
|
rating.y += offsets[1];
|
||||||
|
var styleOffsets = noteStyle.getJudgementSpriteOffsets(daRating);
|
||||||
|
rating.x += styleOffsets[0];
|
||||||
|
rating.y += styleOffsets[1];
|
||||||
|
|
||||||
rating.acceleration.y = 550;
|
rating.acceleration.y = 550;
|
||||||
rating.velocity.y -= FlxG.random.int(140, 175);
|
rating.velocity.y -= FlxG.random.int(140, 175);
|
||||||
|
|
@ -90,9 +98,11 @@ class PopUpStuff extends FlxTypedGroup<FunkinSprite>
|
||||||
trace('numScore($daLoop) = ${numScore.x}');
|
trace('numScore($daLoop) = ${numScore.x}');
|
||||||
numScore.y = (FlxG.camera.height * 0.44);
|
numScore.y = (FlxG.camera.height * 0.44);
|
||||||
|
|
||||||
var offsets = noteStyle.getComboNumSpriteOffsets(digit);
|
|
||||||
numScore.x += offsets[0];
|
numScore.x += offsets[0];
|
||||||
numScore.y += offsets[1];
|
numScore.y += offsets[1];
|
||||||
|
var styleOffsets = noteStyle.getComboNumSpriteOffsets(digit);
|
||||||
|
numScore.x += styleOffsets[0];
|
||||||
|
numScore.y += styleOffsets[1];
|
||||||
|
|
||||||
numScore.acceleration.y = FlxG.random.int(250, 300);
|
numScore.acceleration.y = FlxG.random.int(250, 300);
|
||||||
numScore.velocity.y -= FlxG.random.int(130, 150);
|
numScore.velocity.y -= FlxG.random.int(130, 150);
|
||||||
|
|
|
||||||
|
|
@ -556,40 +556,6 @@ enum abstract ScoringRank(String)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMusicPath():String
|
|
||||||
{
|
|
||||||
switch (abstract)
|
|
||||||
{
|
|
||||||
case PERFECT_GOLD:
|
|
||||||
return 'resultsPERFECT';
|
|
||||||
case PERFECT:
|
|
||||||
return 'resultsPERFECT';
|
|
||||||
case EXCELLENT:
|
|
||||||
return 'resultsEXCELLENT';
|
|
||||||
case GREAT:
|
|
||||||
return 'resultsNORMAL';
|
|
||||||
case GOOD:
|
|
||||||
return 'resultsNORMAL';
|
|
||||||
case SHIT:
|
|
||||||
return 'resultsSHIT';
|
|
||||||
default:
|
|
||||||
return 'resultsNORMAL';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasMusicIntro():Bool
|
|
||||||
{
|
|
||||||
switch (abstract)
|
|
||||||
{
|
|
||||||
case EXCELLENT:
|
|
||||||
return true;
|
|
||||||
case SHIT:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFreeplayRankIconAsset():String
|
public function getFreeplayRankIconAsset():String
|
||||||
{
|
{
|
||||||
switch (abstract)
|
switch (abstract)
|
||||||
|
|
|
||||||
|
|
@ -533,6 +533,28 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
return variation.playData.difficulties.contains(diffId);
|
return variation.playData.difficulties.contains(diffId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of available alternate instrumentals.
|
||||||
|
* Scripts can override this, fun.
|
||||||
|
* @param variationId
|
||||||
|
* @param difficultyId
|
||||||
|
*/
|
||||||
|
public function listAltInstrumentalIds(difficultyId:String, variationId:String):Array<String>
|
||||||
|
{
|
||||||
|
var targetDifficulty:Null<SongDifficulty> = getDifficulty(difficultyId, variationId);
|
||||||
|
if (targetDifficulty == null) return [];
|
||||||
|
|
||||||
|
return targetDifficulty?.characters?.altInstrumentals ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseInstrumentalId(difficultyId:String, variationId:String):String
|
||||||
|
{
|
||||||
|
var targetDifficulty:Null<SongDifficulty> = getDifficulty(difficultyId, variationId);
|
||||||
|
if (targetDifficulty == null) return '';
|
||||||
|
|
||||||
|
return targetDifficulty?.characters?.instrumental ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purge the cached chart data for each difficulty of this song.
|
* Purge the cached chart data for each difficulty of this song.
|
||||||
*/
|
*/
|
||||||
|
|
@ -851,7 +873,7 @@ class SongDifficulty
|
||||||
* @param charId The player ID.
|
* @param charId The player ID.
|
||||||
* @return The generated vocal group.
|
* @return The generated vocal group.
|
||||||
*/
|
*/
|
||||||
public function buildVocals():VoicesGroup
|
public function buildVocals(?instId:String = ''):VoicesGroup
|
||||||
{
|
{
|
||||||
var result:VoicesGroup = new VoicesGroup();
|
var result:VoicesGroup = new VoicesGroup();
|
||||||
|
|
||||||
|
|
@ -870,8 +892,8 @@ class SongDifficulty
|
||||||
result.addOpponentVoice(FunkinSound.load(opponentVoice));
|
result.addOpponentVoice(FunkinSound.load(opponentVoice));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.playerVoicesOffset = offsets.getVocalOffset(characters.player);
|
result.playerVoicesOffset = offsets.getVocalOffset(characters.player, instId);
|
||||||
result.opponentVoicesOffset = offsets.getVocalOffset(characters.opponent);
|
result.opponentVoicesOffset = offsets.getVocalOffset(characters.opponent, instId);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@ import flixel.math.FlxMath;
|
||||||
import funkin.util.FramesJSFLParser;
|
import funkin.util.FramesJSFLParser;
|
||||||
import funkin.util.FramesJSFLParser.FramesJSFLInfo;
|
import funkin.util.FramesJSFLParser.FramesJSFLInfo;
|
||||||
import funkin.util.FramesJSFLParser.FramesJSFLFrame;
|
import funkin.util.FramesJSFLParser.FramesJSFLFrame;
|
||||||
|
import funkin.modding.IScriptedClass.IBPMSyncedScriptedClass;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.vis.dsp.SpectralAnalyzer;
|
import funkin.vis.dsp.SpectralAnalyzer;
|
||||||
|
|
||||||
class CharSelectGF extends FlxAtlasSprite
|
class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
||||||
{
|
{
|
||||||
var fadeTimer:Float = 0;
|
var fadeTimer:Float = 0;
|
||||||
var fadingStatus:FadeStatus = OFF;
|
var fadingStatus:FadeStatus = OFF;
|
||||||
|
|
@ -54,6 +56,7 @@ class CharSelectGF extends FlxAtlasSprite
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FEATURE_DEBUG_FUNCTIONS
|
||||||
if (FlxG.keys.justPressed.J)
|
if (FlxG.keys.justPressed.J)
|
||||||
{
|
{
|
||||||
alpha = 1;
|
alpha = 1;
|
||||||
|
|
@ -65,8 +68,27 @@ class CharSelectGF extends FlxAtlasSprite
|
||||||
alpha = 0;
|
alpha = 0;
|
||||||
fadingStatus = FADE_IN;
|
fadingStatus = FADE_IN;
|
||||||
}
|
}
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onStepHit(event:SongTimeScriptEvent):Void {}
|
||||||
|
|
||||||
|
var danceEvery:Int = 2;
|
||||||
|
|
||||||
|
public function onBeatHit(event:SongTimeScriptEvent):Void
|
||||||
|
{
|
||||||
|
// TODO: There's a minor visual bug where there's a little stutter.
|
||||||
|
// This happens because the animation is getting restarted while it's already playing.
|
||||||
|
// I tried make this not interrupt an existing idle,
|
||||||
|
// but isAnimationFinished() and isLoopComplete() both don't work! What the hell?
|
||||||
|
// danceEvery isn't necessary if that gets fixed.
|
||||||
|
if (getCurrentAnimation() == "idle" && (event.beat % danceEvery == 0))
|
||||||
|
{
|
||||||
|
trace('GF beat hit');
|
||||||
|
playAnimation("idle", true, false, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
override public function draw()
|
override public function draw()
|
||||||
{
|
{
|
||||||
if (analyzer != null) drawFFT();
|
if (analyzer != null) drawFFT();
|
||||||
|
|
@ -87,7 +109,9 @@ class CharSelectGF extends FlxAtlasSprite
|
||||||
var animFrame:Int = Math.round(levels[i].value * 12);
|
var animFrame:Int = Math.round(levels[i].value * 12);
|
||||||
|
|
||||||
#if desktop
|
#if desktop
|
||||||
animFrame = Math.round(animFrame * FlxG.sound.volume);
|
// Web version scales with the Flixel volume level.
|
||||||
|
// This line brings platform parity but looks worse.
|
||||||
|
// animFrame = Math.round(animFrame * FlxG.sound.volume);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
animFrame = Math.floor(Math.min(12, animFrame));
|
animFrame = Math.floor(Math.min(12, animFrame));
|
||||||
|
|
@ -160,18 +184,27 @@ class CharSelectGF extends FlxAtlasSprite
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't need to update any anims if we didn't change GF
|
// We don't need to update any anims if we didn't change GF
|
||||||
if (prevGF == curGF) return;
|
if (prevGF != curGF)
|
||||||
|
{
|
||||||
|
loadAtlas(Paths.animateAtlas("charSelect/" + curGF + "Chill"));
|
||||||
|
|
||||||
loadAtlas(Paths.animateAtlas("charSelect/" + curGF + "Chill"));
|
animInInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "In.txt"));
|
||||||
|
animOutInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "Out.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
animInInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "In.txt"));
|
playAnimation("idle", true, false, false);
|
||||||
animOutInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "Out.txt"));
|
|
||||||
|
|
||||||
playAnimation("idle", true, false, true);
|
|
||||||
// addFrameCallback(getNextFrameLabel("idle"), () -> playAnimation("idle", true, false, false));
|
// addFrameCallback(getNextFrameLabel("idle"), () -> playAnimation("idle", true, false, false));
|
||||||
|
|
||||||
updateHitbox();
|
updateHitbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onScriptEvent(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onCreate(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onDestroy(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onUpdate(event:UpdateScriptEvent):Void {};
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FadeStatus
|
enum FadeStatus
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ package funkin.ui.charSelect;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
import flxanimate.animate.FlxKeyFrame;
|
import flxanimate.animate.FlxKeyFrame;
|
||||||
|
import funkin.modding.IScriptedClass.IBPMSyncedScriptedClass;
|
||||||
|
import funkin.modding.events.ScriptEvent;
|
||||||
|
|
||||||
class CharSelectPlayer extends FlxAtlasSprite
|
class CharSelectPlayer extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
||||||
{
|
{
|
||||||
var desLp:FlxKeyFrame = null;
|
var desLp:FlxKeyFrame = null;
|
||||||
|
|
||||||
|
|
@ -18,11 +20,19 @@ class CharSelectPlayer extends FlxAtlasSprite
|
||||||
switch (animLabel)
|
switch (animLabel)
|
||||||
{
|
{
|
||||||
case "slidein":
|
case "slidein":
|
||||||
if (hasAnimation("slidein idle point")) playAnimation("slidein idle point", true, false, false);
|
if (hasAnimation("slidein idle point"))
|
||||||
|
{
|
||||||
|
playAnimation("slidein idle point", true, false, false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
playAnimation("idle", true, false, true);
|
playAnimation("idle", true, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
case "slidein idle point", "cannot select", "unlock":
|
case "slidein idle point", "cannot select", "unlock":
|
||||||
playAnimation("idle", true, false, true);
|
playAnimation("idle", true, false, true);
|
||||||
|
case "idle":
|
||||||
|
trace('Waiting for onBeatHit');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -31,6 +41,22 @@ class CharSelectPlayer extends FlxAtlasSprite
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onStepHit(event:SongTimeScriptEvent):Void {}
|
||||||
|
|
||||||
|
public function onBeatHit(event:SongTimeScriptEvent):Void
|
||||||
|
{
|
||||||
|
// TODO: There's a minor visual bug where there's a little stutter.
|
||||||
|
// This happens because the animation is getting restarted while it's already playing.
|
||||||
|
// I tried make this not interrupt an existing idle,
|
||||||
|
// but isAnimationFinished() and isLoopComplete() both don't work! What the hell?
|
||||||
|
// danceEvery isn't necessary if that gets fixed.
|
||||||
|
if (getCurrentAnimation() == "idle")
|
||||||
|
{
|
||||||
|
trace('Player beat hit');
|
||||||
|
playAnimation("idle", true, false, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public function updatePosition(str:String)
|
public function updatePosition(str:String)
|
||||||
{
|
{
|
||||||
switch (str)
|
switch (str)
|
||||||
|
|
@ -61,4 +87,12 @@ class CharSelectPlayer extends FlxAtlasSprite
|
||||||
|
|
||||||
updatePosition(str);
|
updatePosition(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onScriptEvent(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onCreate(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onDestroy(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onUpdate(event:UpdateScriptEvent):Void {};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,11 @@ import funkin.data.freeplay.player.PlayerRegistry;
|
||||||
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
import openfl.filters.DropShadowFilter;
|
import openfl.filters.DropShadowFilter;
|
||||||
import funkin.graphics.FunkinCamera;
|
import funkin.graphics.FunkinCamera;
|
||||||
|
import funkin.graphics.shaders.BlueFade;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
import funkin.modding.events.ScriptEventDispatcher;
|
||||||
import funkin.play.stage.Stage;
|
import funkin.play.stage.Stage;
|
||||||
|
import funkin.save.Save;
|
||||||
import funkin.ui.freeplay.charselect.PlayableCharacter;
|
import funkin.ui.freeplay.charselect.PlayableCharacter;
|
||||||
import funkin.ui.freeplay.FreeplayState;
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
import funkin.ui.PixelatedIcon;
|
import funkin.ui.PixelatedIcon;
|
||||||
|
|
@ -28,6 +30,7 @@ import funkin.util.MathUtil;
|
||||||
import funkin.vis.dsp.SpectralAnalyzer;
|
import funkin.vis.dsp.SpectralAnalyzer;
|
||||||
import openfl.display.BlendMode;
|
import openfl.display.BlendMode;
|
||||||
import funkin.save.Save;
|
import funkin.save.Save;
|
||||||
|
import openfl.filters.ShaderFilter;
|
||||||
|
|
||||||
class CharSelectSubState extends MusicBeatSubState
|
class CharSelectSubState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
|
|
@ -59,9 +62,16 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
var gfChill:CharSelectGF;
|
var gfChill:CharSelectGF;
|
||||||
var gfChillOut:CharSelectGF;
|
var gfChillOut:CharSelectGF;
|
||||||
|
|
||||||
|
var barthing:FlxAtlasSprite;
|
||||||
|
var dipshitBacking:FlxSprite;
|
||||||
|
var chooseDipshit:FlxSprite;
|
||||||
|
var dipshitBlur:FlxSprite;
|
||||||
|
var transitionGradient:FlxSprite;
|
||||||
|
|
||||||
var curChar(default, set):String = "pico";
|
var curChar(default, set):String = "pico";
|
||||||
var nametag:Nametag;
|
var nametag:Nametag;
|
||||||
var camFollow:FlxObject;
|
var camFollow:FlxObject;
|
||||||
|
var autoFollow:Bool = false;
|
||||||
|
|
||||||
var availableChars:Map<Int, String> = new Map<Int, String>();
|
var availableChars:Map<Int, String> = new Map<Int, String>();
|
||||||
var pressedSelect:Bool = false;
|
var pressedSelect:Bool = false;
|
||||||
|
|
@ -102,6 +112,8 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fadeShader:BlueFade = new BlueFade();
|
||||||
|
|
||||||
override public function create():Void
|
override public function create():Void
|
||||||
{
|
{
|
||||||
super.create();
|
super.create();
|
||||||
|
|
@ -118,7 +130,7 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
|
|
||||||
var stageSpr:FlxSprite = new FlxSprite(-40, 391);
|
var stageSpr:FlxSprite = new FlxSprite(-40, 391);
|
||||||
stageSpr.frames = Paths.getSparrowAtlas("charSelect/charSelectStage");
|
stageSpr.frames = Paths.getSparrowAtlas("charSelect/charSelectStage");
|
||||||
stageSpr.animation.addByPrefix("idle", "stage", 24, true);
|
stageSpr.animation.addByPrefix("idle", "stage full instance 1", 24, true);
|
||||||
stageSpr.animation.play("idle");
|
stageSpr.animation.play("idle");
|
||||||
add(stageSpr);
|
add(stageSpr);
|
||||||
|
|
||||||
|
|
@ -127,12 +139,15 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
curtains.scrollFactor.set(1.4, 1.4);
|
curtains.scrollFactor.set(1.4, 1.4);
|
||||||
add(curtains);
|
add(curtains);
|
||||||
|
|
||||||
var barthing:FlxAtlasSprite = new FlxAtlasSprite(0, 0, Paths.animateAtlas("charSelect/barThing"));
|
barthing = new FlxAtlasSprite(0, 0, Paths.animateAtlas("charSelect/barThing"));
|
||||||
barthing.anim.play("");
|
barthing.anim.play("");
|
||||||
barthing.blend = BlendMode.MULTIPLY;
|
barthing.blend = BlendMode.MULTIPLY;
|
||||||
barthing.scrollFactor.set(0, 0);
|
barthing.scrollFactor.set(0, 0);
|
||||||
add(barthing);
|
add(barthing);
|
||||||
|
|
||||||
|
barthing.y += 80;
|
||||||
|
FlxTween.tween(barthing, {y: barthing.y - 80}, 1.3, {ease: FlxEase.expoOut});
|
||||||
|
|
||||||
var charLight:FlxSprite = new FlxSprite(800, 250);
|
var charLight:FlxSprite = new FlxSprite(800, 250);
|
||||||
charLight.loadGraphic(Paths.image('charSelect/charLight'));
|
charLight.loadGraphic(Paths.image('charSelect/charLight'));
|
||||||
add(charLight);
|
add(charLight);
|
||||||
|
|
@ -163,24 +178,33 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
fgBlur.blend = openfl.display.BlendMode.MULTIPLY;
|
fgBlur.blend = openfl.display.BlendMode.MULTIPLY;
|
||||||
add(fgBlur);
|
add(fgBlur);
|
||||||
|
|
||||||
var dipshitBlur:FlxSprite = new FlxSprite(419, -65);
|
dipshitBlur = new FlxSprite(419, -65);
|
||||||
dipshitBlur.frames = Paths.getSparrowAtlas("charSelect/dipshitBlur");
|
dipshitBlur.frames = Paths.getSparrowAtlas("charSelect/dipshitBlur");
|
||||||
dipshitBlur.animation.addByPrefix('idle', "CHOOSE vertical", 24, true);
|
dipshitBlur.animation.addByPrefix('idle', "CHOOSE vertical offset instance 1", 24, true);
|
||||||
dipshitBlur.blend = BlendMode.ADD;
|
dipshitBlur.blend = BlendMode.ADD;
|
||||||
dipshitBlur.animation.play("idle");
|
dipshitBlur.animation.play("idle");
|
||||||
add(dipshitBlur);
|
add(dipshitBlur);
|
||||||
|
|
||||||
var dipshitBacking:FlxSprite = new FlxSprite(423, -17);
|
dipshitBacking = new FlxSprite(423, -17);
|
||||||
dipshitBacking.frames = Paths.getSparrowAtlas("charSelect/dipshitBacking");
|
dipshitBacking.frames = Paths.getSparrowAtlas("charSelect/dipshitBacking");
|
||||||
dipshitBacking.animation.addByPrefix('idle', "CHOOSE horizontal", 24, true);
|
dipshitBacking.animation.addByPrefix('idle', "CHOOSE horizontal offset instance 1", 24, true);
|
||||||
dipshitBacking.blend = BlendMode.ADD;
|
dipshitBacking.blend = BlendMode.ADD;
|
||||||
dipshitBacking.animation.play("idle");
|
dipshitBacking.animation.play("idle");
|
||||||
add(dipshitBacking);
|
add(dipshitBacking);
|
||||||
|
|
||||||
var chooseDipshit:FlxSprite = new FlxSprite(426, -13);
|
dipshitBacking.y += 210;
|
||||||
|
FlxTween.tween(dipshitBacking, {y: dipshitBacking.y - 210}, 1.1, {ease: FlxEase.expoOut});
|
||||||
|
|
||||||
|
chooseDipshit = new FlxSprite(426, -13);
|
||||||
chooseDipshit.loadGraphic(Paths.image('charSelect/chooseDipshit'));
|
chooseDipshit.loadGraphic(Paths.image('charSelect/chooseDipshit'));
|
||||||
add(chooseDipshit);
|
add(chooseDipshit);
|
||||||
|
|
||||||
|
chooseDipshit.y += 200;
|
||||||
|
FlxTween.tween(chooseDipshit, {y: chooseDipshit.y - 200}, 1, {ease: FlxEase.expoOut});
|
||||||
|
|
||||||
|
dipshitBlur.y += 220;
|
||||||
|
FlxTween.tween(dipshitBlur, {y: dipshitBlur.y - 220}, 1.2, {ease: FlxEase.expoOut});
|
||||||
|
|
||||||
chooseDipshit.scrollFactor.set();
|
chooseDipshit.scrollFactor.set();
|
||||||
dipshitBacking.scrollFactor.set();
|
dipshitBacking.scrollFactor.set();
|
||||||
dipshitBlur.scrollFactor.set();
|
dipshitBlur.scrollFactor.set();
|
||||||
|
|
@ -231,14 +255,14 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
cursorConfirmed = new FlxSprite(0, 0);
|
cursorConfirmed = new FlxSprite(0, 0);
|
||||||
cursorConfirmed.scrollFactor.set();
|
cursorConfirmed.scrollFactor.set();
|
||||||
cursorConfirmed.frames = Paths.getSparrowAtlas("charSelect/charSelectorConfirm");
|
cursorConfirmed.frames = Paths.getSparrowAtlas("charSelect/charSelectorConfirm");
|
||||||
cursorConfirmed.animation.addByPrefix("idle", "cursor ACCEPTED", 24, true);
|
cursorConfirmed.animation.addByPrefix("idle", "cursor ACCEPTED instance 1", 24, true);
|
||||||
cursorConfirmed.visible = false;
|
cursorConfirmed.visible = false;
|
||||||
add(cursorConfirmed);
|
add(cursorConfirmed);
|
||||||
|
|
||||||
cursorDenied = new FlxSprite(0, 0);
|
cursorDenied = new FlxSprite(0, 0);
|
||||||
cursorDenied.scrollFactor.set();
|
cursorDenied.scrollFactor.set();
|
||||||
cursorDenied.frames = Paths.getSparrowAtlas("charSelect/charSelectorDenied");
|
cursorDenied.frames = Paths.getSparrowAtlas("charSelect/charSelectorDenied");
|
||||||
cursorDenied.animation.addByPrefix("idle", "cursor DENIED", 24, false);
|
cursorDenied.animation.addByPrefix("idle", "cursor DENIED instance 1", 24, false);
|
||||||
cursorDenied.visible = false;
|
cursorDenied.visible = false;
|
||||||
add(cursorDenied);
|
add(cursorDenied);
|
||||||
|
|
||||||
|
|
@ -248,6 +272,12 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
|
|
||||||
initLocks();
|
initLocks();
|
||||||
|
|
||||||
|
for (index => member in grpIcons.members)
|
||||||
|
{
|
||||||
|
member.y += 300;
|
||||||
|
FlxTween.tween(member, {y: member.y - 300}, 1, {ease: FlxEase.expoOut});
|
||||||
|
}
|
||||||
|
|
||||||
cursor.scrollFactor.set();
|
cursor.scrollFactor.set();
|
||||||
cursorBlue.scrollFactor.set();
|
cursorBlue.scrollFactor.set();
|
||||||
cursorDarkBlue.scrollFactor.set();
|
cursorDarkBlue.scrollFactor.set();
|
||||||
|
|
@ -259,13 +289,12 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
FlxG.debugger.addTrackerProfile(new TrackerProfile(CharSelectSubState, ["curChar", "grpXSpread", "grpYSpread"]));
|
FlxG.debugger.addTrackerProfile(new TrackerProfile(CharSelectSubState, ["curChar", "grpXSpread", "grpYSpread"]));
|
||||||
FlxG.debugger.track(this);
|
FlxG.debugger.track(this);
|
||||||
|
|
||||||
// FlxG.sound.playMusic(Paths.music('charSelect/charSelectMusic'));
|
|
||||||
|
|
||||||
camFollow = new FlxObject(0, 0, 1, 1);
|
camFollow = new FlxObject(0, 0, 1, 1);
|
||||||
add(camFollow);
|
add(camFollow);
|
||||||
camFollow.screenCenter();
|
camFollow.screenCenter();
|
||||||
|
|
||||||
FlxG.camera.follow(camFollow, LOCKON, 0.01);
|
// FlxG.camera.follow(camFollow, LOCKON, 0.01);
|
||||||
|
FlxG.camera.follow(camFollow, LOCKON);
|
||||||
|
|
||||||
var temp:FlxSprite = new FlxSprite();
|
var temp:FlxSprite = new FlxSprite();
|
||||||
temp.loadGraphic(Paths.image('charSelect/placement'));
|
temp.loadGraphic(Paths.image('charSelect/placement'));
|
||||||
|
|
@ -281,6 +310,25 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
|
|
||||||
Conductor.stepHit.add(spamOnStep);
|
Conductor.stepHit.add(spamOnStep);
|
||||||
// FlxG.debugger.track(temp, "tempBG");
|
// FlxG.debugger.track(temp, "tempBG");
|
||||||
|
|
||||||
|
transitionGradient = new FlxSprite(0, 0).loadGraphic(Paths.image('freeplay/transitionGradient'));
|
||||||
|
transitionGradient.scale.set(1280, 1);
|
||||||
|
transitionGradient.flipY = true;
|
||||||
|
transitionGradient.updateHitbox();
|
||||||
|
FlxTween.tween(transitionGradient, {y: -720}, 1, {ease: FlxEase.expoOut});
|
||||||
|
add(transitionGradient);
|
||||||
|
|
||||||
|
camFollow.screenCenter();
|
||||||
|
camFollow.y -= 150;
|
||||||
|
fadeShader.fade(0.0, 1.0, 0.8, {ease: FlxEase.quadOut});
|
||||||
|
FlxTween.tween(camFollow, {y: camFollow.y + 150}, 1.5,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onComplete: function(_) {
|
||||||
|
autoFollow = true;
|
||||||
|
FlxG.camera.follow(camFollow, LOCKON, 0.01);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var grpIcons:FlxSpriteGroup;
|
var grpIcons:FlxSpriteGroup;
|
||||||
|
|
@ -418,6 +466,42 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goToFreeplay():Void
|
||||||
|
{
|
||||||
|
autoFollow = false;
|
||||||
|
|
||||||
|
FlxTween.tween(cursor, {alpha: 0}, 0.8, {ease: FlxEase.expoOut});
|
||||||
|
FlxTween.tween(cursorBlue, {alpha: 0}, 0.8, {ease: FlxEase.expoOut});
|
||||||
|
FlxTween.tween(cursorDarkBlue, {alpha: 0}, 0.8, {ease: FlxEase.expoOut});
|
||||||
|
FlxTween.tween(cursorConfirmed, {alpha: 0}, 0.8, {ease: FlxEase.expoOut});
|
||||||
|
|
||||||
|
FlxTween.tween(barthing, {y: barthing.y + 80}, 0.8, {ease: FlxEase.backIn});
|
||||||
|
FlxTween.tween(dipshitBacking, {y: dipshitBacking.y + 210}, 0.8, {ease: FlxEase.backIn});
|
||||||
|
FlxTween.tween(chooseDipshit, {y: chooseDipshit.y + 200}, 0.8, {ease: FlxEase.backIn});
|
||||||
|
FlxTween.tween(dipshitBlur, {y: dipshitBlur.y + 220}, 0.8, {ease: FlxEase.backIn});
|
||||||
|
for (index => member in grpIcons.members)
|
||||||
|
{
|
||||||
|
// member.y += 300;
|
||||||
|
FlxTween.tween(member, {y: member.y + 300}, 0.8, {ease: FlxEase.backIn});
|
||||||
|
}
|
||||||
|
FlxG.camera.follow(camFollow, LOCKON);
|
||||||
|
FlxTween.tween(transitionGradient, {y: -150}, 0.8, {ease: FlxEase.backIn});
|
||||||
|
fadeShader.fade(1.0, 0, 0.8, {ease: FlxEase.quadIn});
|
||||||
|
FlxTween.tween(camFollow, {y: camFollow.y - 150}, 0.8,
|
||||||
|
{
|
||||||
|
ease: FlxEase.backIn,
|
||||||
|
onComplete: function(_) {
|
||||||
|
FlxG.switchState(FreeplayState.build(
|
||||||
|
{
|
||||||
|
{
|
||||||
|
character: curChar,
|
||||||
|
fromCharSelect: true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var holdTmrUp:Float = 0;
|
var holdTmrUp:Float = 0;
|
||||||
var holdTmrDown:Float = 0;
|
var holdTmrDown:Float = 0;
|
||||||
var holdTmrLeft:Float = 0;
|
var holdTmrLeft:Float = 0;
|
||||||
|
|
@ -534,18 +618,20 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
|
|
||||||
FlxG.sound.play(Paths.sound('CS_confirm'));
|
FlxG.sound.play(Paths.sound('CS_confirm'));
|
||||||
|
|
||||||
FlxTween.tween(FlxG.sound.music, {pitch: 0.1}, 1.5, {ease: FlxEase.quadInOut});
|
FlxTween.tween(FlxG.sound.music, {pitch: 0.1}, 1, {ease: FlxEase.quadInOut});
|
||||||
|
FlxTween.tween(FlxG.sound.music, {volume: 0.0}, 1.5, {ease: FlxEase.quadInOut});
|
||||||
playerChill.playAnimation("select");
|
playerChill.playAnimation("select");
|
||||||
gfChill.playAnimation("confirm");
|
gfChill.playAnimation("confirm");
|
||||||
pressedSelect = true;
|
pressedSelect = true;
|
||||||
selectTimer.start(1.5, (_) -> {
|
selectTimer.start(1.5, (_) -> {
|
||||||
pressedSelect = false;
|
pressedSelect = false;
|
||||||
FlxG.switchState(FreeplayState.build(
|
// FlxG.switchState(FreeplayState.build(
|
||||||
{
|
// {
|
||||||
{
|
// {
|
||||||
character: curChar
|
// character: curChar
|
||||||
}
|
// }
|
||||||
}));
|
// }));
|
||||||
|
goToFreeplay();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -555,6 +641,7 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
grpCursors.visible = true;
|
grpCursors.visible = true;
|
||||||
|
|
||||||
FlxTween.globalManager.cancelTweensOf(FlxG.sound.music);
|
FlxTween.globalManager.cancelTweensOf(FlxG.sound.music);
|
||||||
|
FlxTween.tween(FlxG.sound.music, {pitch: 1.0, volume: 1.0}, 1, {ease: FlxEase.quartInOut});
|
||||||
playerChill.playAnimation("deselect");
|
playerChill.playAnimation("deselect");
|
||||||
gfChill.playAnimation("deselect");
|
gfChill.playAnimation("deselect");
|
||||||
FlxTween.tween(FlxG.sound.music, {pitch: 1.0}, 1,
|
FlxTween.tween(FlxG.sound.music, {pitch: 1.0}, 1,
|
||||||
|
|
@ -587,9 +674,12 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
|
|
||||||
updateLockAnims();
|
updateLockAnims();
|
||||||
|
|
||||||
camFollow.screenCenter();
|
if (autoFollow == true)
|
||||||
camFollow.x += cursorX * 10;
|
{
|
||||||
camFollow.y += cursorY * 10;
|
camFollow.screenCenter();
|
||||||
|
camFollow.x += cursorX * 10;
|
||||||
|
camFollow.y += cursorY * 10;
|
||||||
|
}
|
||||||
|
|
||||||
cursorLocIntended.x = (cursorFactor * cursorX) + (FlxG.width / 2) - cursor.width / 2;
|
cursorLocIntended.x = (cursorFactor * cursorX) + (FlxG.width / 2) - cursor.width / 2;
|
||||||
cursorLocIntended.y = (cursorFactor * cursorY) + (FlxG.height / 2) - cursor.height / 2;
|
cursorLocIntended.y = (cursorFactor * cursorY) + (FlxG.height / 2) - cursor.height / 2;
|
||||||
|
|
@ -607,6 +697,16 @@ class CharSelectSubState extends MusicBeatSubState
|
||||||
cursorDarkBlue.y = MathUtil.coolLerp(cursorDarkBlue.y, cursorLocIntended.y, lerpAmnt * 0.2);
|
cursorDarkBlue.y = MathUtil.coolLerp(cursorDarkBlue.y, cursorLocIntended.y, lerpAmnt * 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function dispatchEvent(event:ScriptEvent):Void
|
||||||
|
{
|
||||||
|
// super.dispatchEvent(event) dispatches event to module scripts.
|
||||||
|
super.dispatchEvent(event);
|
||||||
|
|
||||||
|
// Dispatch events (like onBeatHit) to props
|
||||||
|
ScriptEventDispatcher.callEvent(playerChill, event);
|
||||||
|
ScriptEventDispatcher.callEvent(gfChill, event);
|
||||||
|
}
|
||||||
|
|
||||||
function spamOnStep():Void
|
function spamOnStep():Void
|
||||||
{
|
{
|
||||||
if (FlxG.keys.justPressed.B)
|
if (FlxG.keys.justPressed.B)
|
||||||
|
|
|
||||||
|
|
@ -5713,7 +5713,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
PlayStatePlaylist.campaignId = 'week6';
|
PlayStatePlaylist.campaignId = 'week6';
|
||||||
case 'tankmanBattlefield':
|
case 'tankmanBattlefield':
|
||||||
PlayStatePlaylist.campaignId = 'week7';
|
PlayStatePlaylist.campaignId = 'week7';
|
||||||
case 'phillyStreets' | 'phillyBlazin' | 'phillyBlazin2':
|
case 'phillyStreets' | 'phillyStreetsErect' | 'phillyBlazin' | 'phillyBlazin2':
|
||||||
PlayStatePlaylist.campaignId = 'weekend1';
|
PlayStatePlaylist.campaignId = 'weekend1';
|
||||||
}
|
}
|
||||||
Paths.setCurrentLevel(PlayStatePlaylist.campaignId);
|
Paths.setCurrentLevel(PlayStatePlaylist.campaignId);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class AlbumRoll extends FlxSpriteGroup
|
||||||
|
|
||||||
var difficultyStars:DifficultyStars;
|
var difficultyStars:DifficultyStars;
|
||||||
var _exitMovers:Null<FreeplayState.ExitMoverData>;
|
var _exitMovers:Null<FreeplayState.ExitMoverData>;
|
||||||
|
var _exitMoversCharSel:Null<FreeplayState.ExitMoverData>;
|
||||||
|
|
||||||
var albumData:Album;
|
var albumData:Album;
|
||||||
|
|
||||||
|
|
@ -128,7 +129,7 @@ class AlbumRoll extends FlxSpriteGroup
|
||||||
* Apply exit movers for the album roll.
|
* Apply exit movers for the album roll.
|
||||||
* @param exitMovers The exit movers to apply.
|
* @param exitMovers The exit movers to apply.
|
||||||
*/
|
*/
|
||||||
public function applyExitMovers(?exitMovers:FreeplayState.ExitMoverData):Void
|
public function applyExitMovers(?exitMovers:FreeplayState.ExitMoverData, ?exitMoversCharSel:FreeplayState.ExitMoverData):Void
|
||||||
{
|
{
|
||||||
if (exitMovers == null)
|
if (exitMovers == null)
|
||||||
{
|
{
|
||||||
|
|
@ -141,12 +142,30 @@ class AlbumRoll extends FlxSpriteGroup
|
||||||
|
|
||||||
if (exitMovers == null) return;
|
if (exitMovers == null) return;
|
||||||
|
|
||||||
|
if (exitMoversCharSel == null)
|
||||||
|
{
|
||||||
|
exitMoversCharSel = _exitMoversCharSel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_exitMoversCharSel = exitMoversCharSel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exitMoversCharSel == null) return;
|
||||||
|
|
||||||
exitMovers.set([newAlbumArt, difficultyStars],
|
exitMovers.set([newAlbumArt, difficultyStars],
|
||||||
{
|
{
|
||||||
x: FlxG.width,
|
x: FlxG.width,
|
||||||
speed: 0.4,
|
speed: 0.4,
|
||||||
wait: 0
|
wait: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([newAlbumArt, difficultyStars],
|
||||||
|
{
|
||||||
|
y: -175,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var titleTimer:Null<FlxTimer> = null;
|
var titleTimer:Null<FlxTimer> = null;
|
||||||
|
|
@ -207,6 +226,13 @@ class AlbumRoll extends FlxSpriteGroup
|
||||||
speed: 0.4,
|
speed: 0.4,
|
||||||
wait: 0
|
wait: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (_exitMoversCharSel != null) _exitMoversCharSel.set([albumTitle],
|
||||||
|
{
|
||||||
|
y: -190,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDifficultyStars(?difficulty:Int):Void
|
public function setDifficultyStars(?difficulty:Int):Void
|
||||||
|
|
|
||||||
176
source/funkin/ui/freeplay/CapsuleOptionsMenu.hx
Normal file
176
source/funkin/ui/freeplay/CapsuleOptionsMenu.hx
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
package funkin.ui.freeplay;
|
||||||
|
|
||||||
|
import funkin.graphics.shaders.PureColor;
|
||||||
|
import funkin.input.Controls;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.util.FlxTimer;
|
||||||
|
import flixel.text.FlxText;
|
||||||
|
import flixel.text.FlxText.FlxTextAlign;
|
||||||
|
|
||||||
|
@:nullSafety
|
||||||
|
class CapsuleOptionsMenu extends FlxSpriteGroup
|
||||||
|
{
|
||||||
|
var capsuleMenuBG:FunkinSprite;
|
||||||
|
var parent:FreeplayState;
|
||||||
|
|
||||||
|
var queueDestroy:Bool = false;
|
||||||
|
|
||||||
|
var instrumentalIds:Array<String> = [''];
|
||||||
|
var currentInstrumentalIndex:Int = 0;
|
||||||
|
|
||||||
|
var currentInstrumental:FlxText;
|
||||||
|
|
||||||
|
public function new(parent:FreeplayState, x:Float = 0, y:Float = 0, instIds:Array<String>):Void
|
||||||
|
{
|
||||||
|
super(x, y);
|
||||||
|
|
||||||
|
this.parent = parent;
|
||||||
|
this.instrumentalIds = instIds;
|
||||||
|
|
||||||
|
capsuleMenuBG = FunkinSprite.createSparrow(0, 0, 'freeplay/instBox/instBox');
|
||||||
|
|
||||||
|
capsuleMenuBG.animation.addByPrefix('open', 'open0', 24, false);
|
||||||
|
capsuleMenuBG.animation.addByPrefix('idle', 'idle0', 24, true);
|
||||||
|
capsuleMenuBG.animation.addByPrefix('open', 'open0', 24, false);
|
||||||
|
|
||||||
|
currentInstrumental = new FlxText(0, 36, capsuleMenuBG.width, '');
|
||||||
|
currentInstrumental.setFormat('VCR OSD Mono', 40, FlxTextAlign.CENTER, true);
|
||||||
|
|
||||||
|
final PAD = 4;
|
||||||
|
var leftArrow = new InstrumentalSelector(parent, PAD, 30, false, parent.getControls());
|
||||||
|
var rightArrow = new InstrumentalSelector(parent, capsuleMenuBG.width - leftArrow.width - PAD, 30, true, parent.getControls());
|
||||||
|
|
||||||
|
var label:FlxText = new FlxText(0, 5, capsuleMenuBG.width, 'INSTRUMENTAL');
|
||||||
|
label.setFormat('VCR OSD Mono', 24, FlxTextAlign.CENTER, true);
|
||||||
|
|
||||||
|
add(capsuleMenuBG);
|
||||||
|
add(leftArrow);
|
||||||
|
add(rightArrow);
|
||||||
|
add(label);
|
||||||
|
add(currentInstrumental);
|
||||||
|
|
||||||
|
capsuleMenuBG.animation.finishCallback = function(_) {
|
||||||
|
capsuleMenuBG.animation.play('idle', true);
|
||||||
|
};
|
||||||
|
capsuleMenuBG.animation.play('open', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (queueDestroy)
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@:privateAccess
|
||||||
|
if (parent.controls.BACK)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var changedInst = false;
|
||||||
|
if (parent.getControls().UI_LEFT_P)
|
||||||
|
{
|
||||||
|
currentInstrumentalIndex = (currentInstrumentalIndex + 1) % instrumentalIds.length;
|
||||||
|
changedInst = true;
|
||||||
|
}
|
||||||
|
if (parent.getControls().UI_RIGHT_P)
|
||||||
|
{
|
||||||
|
currentInstrumentalIndex = (currentInstrumentalIndex - 1 + instrumentalIds.length) % instrumentalIds.length;
|
||||||
|
changedInst = true;
|
||||||
|
}
|
||||||
|
if (!changedInst && currentInstrumental.text == '') changedInst = true;
|
||||||
|
|
||||||
|
if (changedInst)
|
||||||
|
{
|
||||||
|
currentInstrumental.text = instrumentalIds[currentInstrumentalIndex].toTitleCase() ?? '';
|
||||||
|
if (currentInstrumental.text == '') currentInstrumental.text = 'Default';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.getControls().ACCEPT)
|
||||||
|
{
|
||||||
|
onConfirm(instrumentalIds[currentInstrumentalIndex] ?? '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close():Void
|
||||||
|
{
|
||||||
|
// Play in reverse.
|
||||||
|
capsuleMenuBG.animation.play('open', true, true);
|
||||||
|
capsuleMenuBG.animation.finishCallback = function(_) {
|
||||||
|
parent.cleanupCapsuleOptionsMenu();
|
||||||
|
queueDestroy = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override this with `capsuleOptionsMenu.onConfirm = myFunction;`
|
||||||
|
*/
|
||||||
|
public dynamic function onConfirm(targetInstId:String):Void
|
||||||
|
{
|
||||||
|
throw 'onConfirm not implemented!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The difficulty selector arrows to the left and right of the difficulty.
|
||||||
|
*/
|
||||||
|
class InstrumentalSelector extends FunkinSprite
|
||||||
|
{
|
||||||
|
var controls:Controls;
|
||||||
|
var whiteShader:PureColor;
|
||||||
|
|
||||||
|
var parent:FreeplayState;
|
||||||
|
|
||||||
|
var baseScale:Float = 0.6;
|
||||||
|
|
||||||
|
public function new(parent:FreeplayState, x:Float, y:Float, flipped:Bool, controls:Controls)
|
||||||
|
{
|
||||||
|
super(x, y);
|
||||||
|
|
||||||
|
this.parent = parent;
|
||||||
|
|
||||||
|
this.controls = controls;
|
||||||
|
|
||||||
|
frames = Paths.getSparrowAtlas('freeplay/freeplaySelector');
|
||||||
|
animation.addByPrefix('shine', 'arrow pointer loop', 24);
|
||||||
|
animation.play('shine');
|
||||||
|
|
||||||
|
whiteShader = new PureColor(FlxColor.WHITE);
|
||||||
|
|
||||||
|
shader = whiteShader;
|
||||||
|
|
||||||
|
flipX = flipped;
|
||||||
|
|
||||||
|
scale.x = scale.y = 1 * baseScale;
|
||||||
|
updateHitbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
override function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
if (flipX && controls.UI_RIGHT_P) moveShitDown();
|
||||||
|
if (!flipX && controls.UI_LEFT_P) moveShitDown();
|
||||||
|
|
||||||
|
super.update(elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveShitDown():Void
|
||||||
|
{
|
||||||
|
offset.y -= 5;
|
||||||
|
|
||||||
|
whiteShader.colorSet = true;
|
||||||
|
|
||||||
|
scale.x = scale.y = 0.5 * baseScale;
|
||||||
|
|
||||||
|
new FlxTimer().start(2 / 24, function(tmr) {
|
||||||
|
scale.x = scale.y = 1 * baseScale;
|
||||||
|
whiteShader.colorSet = false;
|
||||||
|
updateHitbox();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import flixel.tweens.FlxEase;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import openfl.display.BlendMode;
|
import openfl.display.BlendMode;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
|
||||||
class CapsuleText extends FlxSpriteGroup
|
class CapsuleText extends FlxSpriteGroup
|
||||||
{
|
{
|
||||||
|
|
@ -25,6 +26,8 @@ class CapsuleText extends FlxSpriteGroup
|
||||||
|
|
||||||
public var tooLong:Bool = false;
|
public var tooLong:Bool = false;
|
||||||
|
|
||||||
|
var glowColor:FlxColor = 0xFF00ccff;
|
||||||
|
|
||||||
// 255, 27 normal
|
// 255, 27 normal
|
||||||
// 220, 27 favourited
|
// 220, 27 favourited
|
||||||
|
|
||||||
|
|
@ -38,7 +41,7 @@ class CapsuleText extends FlxSpriteGroup
|
||||||
// whiteText.shader = new GaussianBlurShader(0.3);
|
// whiteText.shader = new GaussianBlurShader(0.3);
|
||||||
text = songTitle;
|
text = songTitle;
|
||||||
|
|
||||||
blurredText.color = 0xFF00ccff;
|
blurredText.color = glowColor;
|
||||||
whiteText.color = 0xFFFFFFFF;
|
whiteText.color = 0xFFFFFFFF;
|
||||||
add(blurredText);
|
add(blurredText);
|
||||||
add(whiteText);
|
add(whiteText);
|
||||||
|
|
@ -51,6 +54,16 @@ class CapsuleText extends FlxSpriteGroup
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function applyStyle(styleData:FreeplayStyle):Void
|
||||||
|
{
|
||||||
|
glowColor = styleData.getCapsuleSelCol();
|
||||||
|
blurredText.color = glowColor;
|
||||||
|
whiteText.textField.filters = [
|
||||||
|
new openfl.filters.GlowFilter(glowColor, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM),
|
||||||
|
// new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// ???? none
|
// ???? none
|
||||||
// 255, 27 normal
|
// 255, 27 normal
|
||||||
// 220, 27 favourited
|
// 220, 27 favourited
|
||||||
|
|
@ -99,7 +112,7 @@ class CapsuleText extends FlxSpriteGroup
|
||||||
whiteText.text = value;
|
whiteText.text = value;
|
||||||
checkClipWidth();
|
checkClipWidth();
|
||||||
whiteText.textField.filters = [
|
whiteText.textField.filters = [
|
||||||
new openfl.filters.GlowFilter(0x00ccff, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM),
|
new openfl.filters.GlowFilter(glowColor, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM),
|
||||||
// new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW)
|
// new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -186,7 +199,7 @@ class CapsuleText extends FlxSpriteGroup
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
blurredText.color = 0xFF00aadd;
|
blurredText.color = glowColor;
|
||||||
whiteText.color = 0xFFDDDDDD;
|
whiteText.color = 0xFFDDDDDD;
|
||||||
whiteText.textField.filters = [
|
whiteText.textField.filters = [
|
||||||
new openfl.filters.GlowFilter(0xDDDDDD, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM),
|
new openfl.filters.GlowFilter(0xDDDDDD, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ class FreeplayDJ extends FlxAtlasSprite
|
||||||
{
|
{
|
||||||
// Represents the sprite's current status.
|
// Represents the sprite's current status.
|
||||||
// Without state machines I would have driven myself crazy years ago.
|
// Without state machines I would have driven myself crazy years ago.
|
||||||
public var currentState:FreeplayDJState = Intro;
|
// Made this PRIVATE so we can keep track of everything that can alter the state!
|
||||||
|
// Add a function to this class if you want to edit this value from outside.
|
||||||
|
private var currentState:FreeplayDJState = Intro;
|
||||||
|
|
||||||
// A callback activated when the intro animation finishes.
|
// A callback activated when the intro animation finishes.
|
||||||
public var onIntroDone:FlxSignal = new FlxSignal();
|
public var onIntroDone:FlxSignal = new FlxSignal();
|
||||||
|
|
@ -378,7 +380,7 @@ class FreeplayDJ extends FlxAtlasSprite
|
||||||
|
|
||||||
public function toCharSelect():Void
|
public function toCharSelect():Void
|
||||||
{
|
{
|
||||||
if (hasAnimation('charSelect'))
|
if (hasAnimation(playableCharData.getAnimationPrefix('charSelect')))
|
||||||
{
|
{
|
||||||
currentState = CharSelect;
|
currentState = CharSelect;
|
||||||
var animPrefix = playableCharData.getAnimationPrefix('charSelect');
|
var animPrefix = playableCharData.getAnimationPrefix('charSelect');
|
||||||
|
|
@ -386,6 +388,7 @@ class FreeplayDJ extends FlxAtlasSprite
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
FlxG.log.warn("Freeplay character does not have 'charSelect' animation!");
|
||||||
currentState = Confirm;
|
currentState = Confirm;
|
||||||
// Call this immediately; otherwise, we get locked out of Character Select.
|
// Call this immediately; otherwise, we get locked out of Character Select.
|
||||||
onCharSelectComplete();
|
onCharSelectComplete();
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,20 @@ class FreeplayScore extends FlxTypedSpriteGroup<ScoreNum>
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function new(x:Float, y:Float, digitCount:Int, scoreShit:Int = 100)
|
public function new(x:Float, y:Float, digitCount:Int, scoreShit:Int = 100, ?styleData:FreeplayStyle)
|
||||||
{
|
{
|
||||||
super(x, y);
|
super(x, y);
|
||||||
|
|
||||||
for (i in 0...digitCount)
|
for (i in 0...digitCount)
|
||||||
{
|
{
|
||||||
add(new ScoreNum(x + (45 * i), y, 0));
|
if (styleData == null)
|
||||||
|
{
|
||||||
|
add(new ScoreNum(x + (45 * i), y, 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
add(new ScoreNum(x + (45 * i), y, 0, styleData));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scoreShit = scoreShit;
|
this.scoreShit = scoreShit;
|
||||||
|
|
@ -76,16 +83,16 @@ class ScoreNum extends FlxSprite
|
||||||
case 1:
|
case 1:
|
||||||
offset.x -= 15;
|
offset.x -= 15;
|
||||||
case 5:
|
case 5:
|
||||||
// set offsets
|
// set offsets
|
||||||
// offset.x += 0;
|
// offset.x += 0;
|
||||||
// offset.y += 10;
|
// offset.y += 10;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
// offset.y += 6;
|
// offset.y += 6;
|
||||||
case 4:
|
case 4:
|
||||||
// offset.y += 5;
|
// offset.y += 5;
|
||||||
case 9:
|
case 9:
|
||||||
// offset.y += 5;
|
// offset.y += 5;
|
||||||
default:
|
default:
|
||||||
centerOffsets(false);
|
centerOffsets(false);
|
||||||
}
|
}
|
||||||
|
|
@ -99,14 +106,21 @@ class ScoreNum extends FlxSprite
|
||||||
|
|
||||||
var numToString:Array<String> = ["ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"];
|
var numToString:Array<String> = ["ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"];
|
||||||
|
|
||||||
public function new(x:Float, y:Float, ?initDigit:Int = 0)
|
public function new(x:Float, y:Float, ?initDigit:Int = 0, ?styleData:FreeplayStyle)
|
||||||
{
|
{
|
||||||
super(x, y);
|
super(x, y);
|
||||||
|
|
||||||
baseY = y;
|
baseY = y;
|
||||||
baseX = x;
|
baseX = x;
|
||||||
|
|
||||||
frames = Paths.getSparrowAtlas('digital_numbers');
|
if (styleData == null)
|
||||||
|
{
|
||||||
|
frames = Paths.getSparrowAtlas('digital_numbers');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frames = Paths.getSparrowAtlas(styleData.getNumbersAssetKey());
|
||||||
|
}
|
||||||
|
|
||||||
for (i in 0...10)
|
for (i in 0...10)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
121
source/funkin/ui/freeplay/FreeplayStyle.hx
Normal file
121
source/funkin/ui/freeplay/FreeplayStyle.hx
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
package funkin.ui.freeplay;
|
||||||
|
|
||||||
|
import funkin.data.freeplay.style.FreeplayStyleData;
|
||||||
|
import funkin.data.freeplay.style.FreeplayStyleRegistry;
|
||||||
|
import funkin.data.animation.AnimationData;
|
||||||
|
import funkin.data.IRegistryEntry;
|
||||||
|
import flixel.graphics.FlxGraphic;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing the data for a style of the Freeplay menu.
|
||||||
|
*/
|
||||||
|
class FreeplayStyle implements IRegistryEntry<FreeplayStyleData>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The internal ID for this freeplay style.
|
||||||
|
*/
|
||||||
|
public final id:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The full data for a freeplay style.
|
||||||
|
*/
|
||||||
|
public final _data:FreeplayStyleData;
|
||||||
|
|
||||||
|
public function new(id:String)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this._data = _fetchData(id);
|
||||||
|
|
||||||
|
if (_data == null)
|
||||||
|
{
|
||||||
|
throw 'Could not parse album data for id: $id';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the background art as a graphic, ready to apply to a sprite.
|
||||||
|
* @return The built graphic
|
||||||
|
*/
|
||||||
|
public function getBgAssetGraphic():FlxGraphic
|
||||||
|
{
|
||||||
|
return FlxG.bitmap.add(Paths.image(getBgAssetKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the asset key for the background.
|
||||||
|
* @return The asset key
|
||||||
|
*/
|
||||||
|
public function getBgAssetKey():String
|
||||||
|
{
|
||||||
|
return _data.bgAsset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the asset key for the background.
|
||||||
|
* @return The asset key
|
||||||
|
*/
|
||||||
|
public function getSelectorAssetKey():String
|
||||||
|
{
|
||||||
|
return _data.selectorAsset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the asset key for the number assets.
|
||||||
|
* @return The asset key
|
||||||
|
*/
|
||||||
|
public function getCapsuleAssetKey():String
|
||||||
|
{
|
||||||
|
return _data.capsuleAsset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the asset key for the capsule art.
|
||||||
|
* @return The asset key
|
||||||
|
*/
|
||||||
|
public function getNumbersAssetKey():String
|
||||||
|
{
|
||||||
|
return _data.numbersAsset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the deselected color of the text outline
|
||||||
|
* for freeplay capsules.
|
||||||
|
* @return The deselected color
|
||||||
|
*/
|
||||||
|
public function getCapsuleDeselCol():FlxColor
|
||||||
|
{
|
||||||
|
return FlxColor.fromString(_data.capsuleTextColors[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the song selection transition delay.
|
||||||
|
* @return The start delay
|
||||||
|
*/
|
||||||
|
public function getStartDelay():Float
|
||||||
|
{
|
||||||
|
return _data.startDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString():String
|
||||||
|
{
|
||||||
|
return 'Style($id)';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the selected color of the text outline
|
||||||
|
* for freeplay capsules.
|
||||||
|
* @return The selected color
|
||||||
|
*/
|
||||||
|
public function getCapsuleSelCol():FlxColor
|
||||||
|
{
|
||||||
|
return FlxColor.fromString(_data.capsuleTextColors[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy():Void {}
|
||||||
|
|
||||||
|
static function _fetchData(id:String):Null<FreeplayStyleData>
|
||||||
|
{
|
||||||
|
return FreeplayStyleRegistry.instance.parseEntryDataWithMigration(id, FreeplayStyleRegistry.instance.fetchEntryVersion(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
9
source/funkin/ui/freeplay/ScriptedFreeplayStyle.hx
Normal file
9
source/funkin/ui/freeplay/ScriptedFreeplayStyle.hx
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
package funkin.ui.freeplay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A script that can be tied to a Freeplay style.
|
||||||
|
* Create a scripted class that extends FreeplayStyle to use this.
|
||||||
|
* This allows you to customize how a specific style works.
|
||||||
|
*/
|
||||||
|
@:hscriptClass
|
||||||
|
class ScriptedFreeplayStyle extends funkin.ui.freeplay.FreeplayStyle implements polymod.hscript.HScriptedClass {}
|
||||||
|
|
@ -88,7 +88,7 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
super(x, y);
|
super(x, y);
|
||||||
|
|
||||||
capsule = new FlxSprite();
|
capsule = new FlxSprite();
|
||||||
capsule.frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule');
|
capsule.frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/capsule/freeplayCapsule');
|
||||||
capsule.animation.addByPrefix('selected', 'mp3 capsule w backing0', 24);
|
capsule.animation.addByPrefix('selected', 'mp3 capsule w backing0', 24);
|
||||||
capsule.animation.addByPrefix('unselected', 'mp3 capsule w backing NOT SELECTED', 24);
|
capsule.animation.addByPrefix('unselected', 'mp3 capsule w backing NOT SELECTED', 24);
|
||||||
// capsule.animation
|
// capsule.animation
|
||||||
|
|
@ -500,12 +500,23 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
updateSelected();
|
updateSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function init(?x:Float, ?y:Float, songData:Null<FreeplaySongData>):Void
|
public function init(?x:Float, ?y:Float, songData:Null<FreeplaySongData>, ?styleData:FreeplayStyle = null):Void
|
||||||
{
|
{
|
||||||
if (x != null) this.x = x;
|
if (x != null) this.x = x;
|
||||||
if (y != null) this.y = y;
|
if (y != null) this.y = y;
|
||||||
this.songData = songData;
|
this.songData = songData;
|
||||||
|
|
||||||
|
// im so mad i have to do this but im pretty sure with the capsules recycling i cant call the new function properly :/
|
||||||
|
// if thats possible someone Please change the new function to be something like
|
||||||
|
// capsule.frames = Paths.getSparrowAtlas(styleData == null ? 'freeplay/freeplayCapsule/capsule/freeplayCapsule' : styleData.getCapsuleAssetKey()); thank u luv u
|
||||||
|
if (styleData != null)
|
||||||
|
{
|
||||||
|
capsule.frames = Paths.getSparrowAtlas(styleData.getCapsuleAssetKey());
|
||||||
|
capsule.animation.addByPrefix('selected', 'mp3 capsule w backing0', 24);
|
||||||
|
capsule.animation.addByPrefix('unselected', 'mp3 capsule w backing NOT SELECTED', 24);
|
||||||
|
songText.applyStyle(styleData);
|
||||||
|
}
|
||||||
|
|
||||||
// Update capsule text.
|
// Update capsule text.
|
||||||
songText.text = songData?.songName ?? 'Random';
|
songText.text = songData?.songName ?? 'Random';
|
||||||
// Update capsule character.
|
// Update capsule character.
|
||||||
|
|
@ -727,7 +738,7 @@ class FreeplayRank extends FlxSprite
|
||||||
switch (val)
|
switch (val)
|
||||||
{
|
{
|
||||||
case SHIT:
|
case SHIT:
|
||||||
// offset.x -= 1;
|
// offset.x -= 1;
|
||||||
case GOOD:
|
case GOOD:
|
||||||
// offset.x -= 1;
|
// offset.x -= 1;
|
||||||
offset.y -= 8;
|
offset.y -= 8;
|
||||||
|
|
@ -735,11 +746,11 @@ class FreeplayRank extends FlxSprite
|
||||||
// offset.x -= 1;
|
// offset.x -= 1;
|
||||||
offset.y -= 8;
|
offset.y -= 8;
|
||||||
case EXCELLENT:
|
case EXCELLENT:
|
||||||
// offset.y += 5;
|
// offset.y += 5;
|
||||||
case PERFECT:
|
case PERFECT:
|
||||||
// offset.y += 5;
|
// offset.y += 5;
|
||||||
case PERFECT_GOLD:
|
case PERFECT_GOLD:
|
||||||
// offset.y += 5;
|
// offset.y += 5;
|
||||||
default:
|
default:
|
||||||
centerOffsets(false);
|
centerOffsets(false);
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
|
@ -796,9 +807,9 @@ class CapsuleNumber extends FlxSprite
|
||||||
case 6:
|
case 6:
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
// offset.y += 5;
|
// offset.y += 5;
|
||||||
case 9:
|
case 9:
|
||||||
// offset.y += 5;
|
// offset.y += 5;
|
||||||
default:
|
default:
|
||||||
centerOffsets(false);
|
centerOffsets(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
249
source/funkin/ui/freeplay/backcards/BackingCard.hx
Normal file
249
source/funkin/ui/freeplay/backcards/BackingCard.hx
Normal file
|
|
@ -0,0 +1,249 @@
|
||||||
|
package funkin.ui.freeplay.backcards;
|
||||||
|
|
||||||
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
|
import flixel.FlxCamera;
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.group.FlxGroup;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||||
|
import flixel.math.FlxAngle;
|
||||||
|
import flixel.math.FlxPoint;
|
||||||
|
import flixel.text.FlxText;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.util.FlxSpriteUtil;
|
||||||
|
import flixel.util.FlxTimer;
|
||||||
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
|
import funkin.ui.freeplay.charselect.PlayableCharacter;
|
||||||
|
import funkin.ui.MusicBeatSubState;
|
||||||
|
import lime.utils.Assets;
|
||||||
|
import openfl.display.BlendMode;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for the backing cards so they dont have to be part of freeplayState......
|
||||||
|
*/
|
||||||
|
class BackingCard extends FlxSpriteGroup
|
||||||
|
{
|
||||||
|
public var backingTextYeah:FlxAtlasSprite;
|
||||||
|
public var orangeBackShit:FunkinSprite;
|
||||||
|
public var alsoOrangeLOL:FunkinSprite;
|
||||||
|
public var pinkBack:FunkinSprite;
|
||||||
|
public var confirmGlow:FlxSprite;
|
||||||
|
public var confirmGlow2:FlxSprite;
|
||||||
|
public var confirmTextGlow:FlxSprite;
|
||||||
|
public var cardGlow:FlxSprite;
|
||||||
|
|
||||||
|
var _exitMovers:Null<FreeplayState.ExitMoverData>;
|
||||||
|
var _exitMoversCharSel:Null<FreeplayState.ExitMoverData>;
|
||||||
|
|
||||||
|
public var instance:FreeplayState;
|
||||||
|
|
||||||
|
public function new(currentCharacter:PlayableCharacter, ?_instance:FreeplayState)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
if (_instance != null) instance = _instance;
|
||||||
|
|
||||||
|
cardGlow = new FlxSprite(-30, -30).loadGraphic(Paths.image('freeplay/cardGlow'));
|
||||||
|
confirmGlow = new FlxSprite(-30, 240).loadGraphic(Paths.image('freeplay/confirmGlow'));
|
||||||
|
confirmTextGlow = new FlxSprite(-8, 115).loadGraphic(Paths.image('freeplay/glowingText'));
|
||||||
|
pinkBack = FunkinSprite.create('freeplay/pinkBack');
|
||||||
|
orangeBackShit = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFFEDA00);
|
||||||
|
alsoOrangeLOL = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFFFD400);
|
||||||
|
confirmGlow2 = new FlxSprite(confirmGlow.x, confirmGlow.y).loadGraphic(Paths.image('freeplay/confirmGlow2'));
|
||||||
|
backingTextYeah = new FlxAtlasSprite(640, 370, Paths.animateAtlas("freeplay/backing-text-yeah"),
|
||||||
|
{
|
||||||
|
FrameRate: 24.0,
|
||||||
|
Reversed: false,
|
||||||
|
// ?OnComplete:Void -> Void,
|
||||||
|
ShowPivot: false,
|
||||||
|
Antialiasing: true,
|
||||||
|
ScrollFactor: new FlxPoint(1, 1),
|
||||||
|
});
|
||||||
|
|
||||||
|
pinkBack.color = 0xFFFFD4E9; // sets it to pink!
|
||||||
|
pinkBack.x -= pinkBack.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply exit movers for the pieces of the backing card.
|
||||||
|
* @param exitMovers The exit movers to apply.
|
||||||
|
*/
|
||||||
|
public function applyExitMovers(?exitMovers:FreeplayState.ExitMoverData, ?exitMoversCharSel:FreeplayState.ExitMoverData):Void
|
||||||
|
{
|
||||||
|
if (exitMovers == null)
|
||||||
|
{
|
||||||
|
exitMovers = _exitMovers;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_exitMovers = exitMovers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exitMovers == null) return;
|
||||||
|
|
||||||
|
if (exitMoversCharSel == null)
|
||||||
|
{
|
||||||
|
exitMoversCharSel = _exitMoversCharSel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_exitMoversCharSel = exitMoversCharSel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exitMoversCharSel == null) return;
|
||||||
|
|
||||||
|
exitMovers.set([pinkBack, orangeBackShit, alsoOrangeLOL],
|
||||||
|
{
|
||||||
|
x: -pinkBack.width,
|
||||||
|
y: pinkBack.y,
|
||||||
|
speed: 0.4,
|
||||||
|
wait: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([pinkBack],
|
||||||
|
{
|
||||||
|
y: -100,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([orangeBackShit, alsoOrangeLOL],
|
||||||
|
{
|
||||||
|
y: -40,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to snap the back of the card to its final position.
|
||||||
|
* Used when returning from character select, as we dont want to play the full animation of everything sliding in.
|
||||||
|
*/
|
||||||
|
public function skipIntroTween():Void
|
||||||
|
{
|
||||||
|
FlxTween.cancelTweensOf(pinkBack);
|
||||||
|
pinkBack.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in create. Adds sprites and tweens.
|
||||||
|
*/
|
||||||
|
public function init():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut});
|
||||||
|
add(pinkBack);
|
||||||
|
|
||||||
|
add(orangeBackShit);
|
||||||
|
|
||||||
|
add(alsoOrangeLOL);
|
||||||
|
|
||||||
|
FlxSpriteUtil.alphaMaskFlxSprite(orangeBackShit, pinkBack, orangeBackShit);
|
||||||
|
orangeBackShit.visible = false;
|
||||||
|
alsoOrangeLOL.visible = false;
|
||||||
|
|
||||||
|
confirmTextGlow.blend = BlendMode.ADD;
|
||||||
|
confirmTextGlow.visible = false;
|
||||||
|
|
||||||
|
confirmGlow.blend = BlendMode.ADD;
|
||||||
|
|
||||||
|
confirmGlow.visible = false;
|
||||||
|
confirmGlow2.visible = false;
|
||||||
|
|
||||||
|
add(confirmGlow2);
|
||||||
|
add(confirmGlow);
|
||||||
|
|
||||||
|
add(confirmTextGlow);
|
||||||
|
|
||||||
|
add(backingTextYeah);
|
||||||
|
|
||||||
|
cardGlow.blend = BlendMode.ADD;
|
||||||
|
cardGlow.visible = false;
|
||||||
|
|
||||||
|
add(cardGlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the dj finishes their start animation.
|
||||||
|
*/
|
||||||
|
public function introDone():Void
|
||||||
|
{
|
||||||
|
pinkBack.color = 0xFFFFD863;
|
||||||
|
orangeBackShit.visible = true;
|
||||||
|
alsoOrangeLOL.visible = true;
|
||||||
|
cardGlow.visible = true;
|
||||||
|
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when selecting a song.
|
||||||
|
*/
|
||||||
|
public function confirm():Void
|
||||||
|
{
|
||||||
|
FlxTween.color(pinkBack, 0.33, 0xFFFFD0D5, 0xFF171831, {ease: FlxEase.quadOut});
|
||||||
|
orangeBackShit.visible = false;
|
||||||
|
alsoOrangeLOL.visible = false;
|
||||||
|
|
||||||
|
confirmGlow.visible = true;
|
||||||
|
confirmGlow2.visible = true;
|
||||||
|
|
||||||
|
backingTextYeah.anim.play("");
|
||||||
|
confirmGlow2.alpha = 0;
|
||||||
|
confirmGlow.alpha = 0;
|
||||||
|
|
||||||
|
FlxTween.color(instance.bgDad, 0.5, 0xFFA8A8A8, 0xFF646464,
|
||||||
|
{
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
FlxTween.tween(confirmGlow2, {alpha: 0.5}, 0.33,
|
||||||
|
{
|
||||||
|
ease: FlxEase.quadOut,
|
||||||
|
onComplete: function(_) {
|
||||||
|
confirmGlow2.alpha = 0.6;
|
||||||
|
confirmGlow.alpha = 1;
|
||||||
|
confirmTextGlow.visible = true;
|
||||||
|
confirmTextGlow.alpha = 1;
|
||||||
|
FlxTween.tween(confirmTextGlow, {alpha: 0.4}, 0.5);
|
||||||
|
FlxTween.tween(confirmGlow, {alpha: 0}, 0.5);
|
||||||
|
FlxTween.color(instance.bgDad, 2, 0xFFCDCDCD, 0xFF555555,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when entering character select, does nothing by default.
|
||||||
|
*/
|
||||||
|
public function enterCharSel():Void {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on each beat in freeplay state.
|
||||||
|
*/
|
||||||
|
public function beatHit():Void {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when exiting the freeplay menu.
|
||||||
|
*/
|
||||||
|
public function disappear():Void
|
||||||
|
{
|
||||||
|
FlxTween.color(pinkBack, 0.25, 0xFFFFD863, 0xFFFFD0D5, {ease: FlxEase.quadOut});
|
||||||
|
|
||||||
|
cardGlow.visible = true;
|
||||||
|
cardGlow.alpha = 1;
|
||||||
|
cardGlow.scale.set(1, 1);
|
||||||
|
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.25, {ease: FlxEase.sineOut});
|
||||||
|
|
||||||
|
orangeBackShit.visible = false;
|
||||||
|
alsoOrangeLOL.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
238
source/funkin/ui/freeplay/backcards/BoyfriendCard.hx
Normal file
238
source/funkin/ui/freeplay/backcards/BoyfriendCard.hx
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
package funkin.ui.freeplay.backcards;
|
||||||
|
|
||||||
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
|
import flixel.FlxCamera;
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.group.FlxGroup;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||||
|
import flixel.math.FlxAngle;
|
||||||
|
import flixel.math.FlxPoint;
|
||||||
|
import flixel.text.FlxText;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.util.FlxSpriteUtil;
|
||||||
|
import flixel.util.FlxTimer;
|
||||||
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
|
import funkin.ui.freeplay.charselect.PlayableCharacter;
|
||||||
|
import funkin.ui.MusicBeatSubState;
|
||||||
|
import lime.utils.Assets;
|
||||||
|
import openfl.display.BlendMode;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
|
||||||
|
class BoyfriendCard extends BackingCard
|
||||||
|
{
|
||||||
|
public var moreWays:BGScrollingText;
|
||||||
|
public var funnyScroll:BGScrollingText;
|
||||||
|
public var txtNuts:BGScrollingText;
|
||||||
|
public var funnyScroll2:BGScrollingText;
|
||||||
|
public var moreWays2:BGScrollingText;
|
||||||
|
public var funnyScroll3:BGScrollingText;
|
||||||
|
|
||||||
|
var glow:FlxSprite;
|
||||||
|
var glowDark:FlxSprite;
|
||||||
|
|
||||||
|
public override function applyExitMovers(?exitMovers:FreeplayState.ExitMoverData, ?exitMoversCharSel:FreeplayState.ExitMoverData):Void
|
||||||
|
{
|
||||||
|
super.applyExitMovers(exitMovers, exitMoversCharSel);
|
||||||
|
if (exitMovers == null || exitMoversCharSel == null) return;
|
||||||
|
exitMovers.set([moreWays],
|
||||||
|
{
|
||||||
|
x: FlxG.width * 2,
|
||||||
|
speed: 0.4,
|
||||||
|
});
|
||||||
|
exitMovers.set([funnyScroll],
|
||||||
|
{
|
||||||
|
x: -funnyScroll.width * 2,
|
||||||
|
y: funnyScroll.y,
|
||||||
|
speed: 0.4,
|
||||||
|
wait: 0
|
||||||
|
});
|
||||||
|
exitMovers.set([txtNuts],
|
||||||
|
{
|
||||||
|
x: FlxG.width * 2,
|
||||||
|
speed: 0.4,
|
||||||
|
});
|
||||||
|
exitMovers.set([funnyScroll2],
|
||||||
|
{
|
||||||
|
x: -funnyScroll2.width * 2,
|
||||||
|
speed: 0.5,
|
||||||
|
});
|
||||||
|
exitMovers.set([moreWays2],
|
||||||
|
{
|
||||||
|
x: FlxG.width * 2,
|
||||||
|
speed: 0.4
|
||||||
|
});
|
||||||
|
exitMovers.set([funnyScroll3],
|
||||||
|
{
|
||||||
|
x: -funnyScroll3.width * 2,
|
||||||
|
speed: 0.3
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([moreWays, funnyScroll, txtNuts, funnyScroll2, moreWays2, funnyScroll3],
|
||||||
|
{
|
||||||
|
y: -60,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function enterCharSel():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(funnyScroll, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(funnyScroll2, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(moreWays, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(moreWays2, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(txtNuts, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(funnyScroll3, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function new(currentCharacter:PlayableCharacter)
|
||||||
|
{
|
||||||
|
super(currentCharacter);
|
||||||
|
|
||||||
|
funnyScroll = new BGScrollingText(0, 220, currentCharacter.getFreeplayDJText(1), FlxG.width / 2, false, 60);
|
||||||
|
funnyScroll2 = new BGScrollingText(0, 335, currentCharacter.getFreeplayDJText(1), FlxG.width / 2, false, 60);
|
||||||
|
moreWays = new BGScrollingText(0, 160, currentCharacter.getFreeplayDJText(2), FlxG.width, true, 43);
|
||||||
|
moreWays2 = new BGScrollingText(0, 397, currentCharacter.getFreeplayDJText(2), FlxG.width, true, 43);
|
||||||
|
txtNuts = new BGScrollingText(0, 285, currentCharacter.getFreeplayDJText(3), FlxG.width / 2, true, 43);
|
||||||
|
funnyScroll3 = new BGScrollingText(0, orangeBackShit.y + 10, currentCharacter.getFreeplayDJText(1), FlxG.width / 2, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function init():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut});
|
||||||
|
add(pinkBack);
|
||||||
|
|
||||||
|
add(orangeBackShit);
|
||||||
|
|
||||||
|
add(alsoOrangeLOL);
|
||||||
|
|
||||||
|
FlxSpriteUtil.alphaMaskFlxSprite(orangeBackShit, pinkBack, orangeBackShit);
|
||||||
|
orangeBackShit.visible = false;
|
||||||
|
alsoOrangeLOL.visible = false;
|
||||||
|
|
||||||
|
confirmTextGlow.blend = BlendMode.ADD;
|
||||||
|
confirmTextGlow.visible = false;
|
||||||
|
|
||||||
|
confirmGlow.blend = BlendMode.ADD;
|
||||||
|
|
||||||
|
confirmGlow.visible = false;
|
||||||
|
confirmGlow2.visible = false;
|
||||||
|
|
||||||
|
add(confirmGlow2);
|
||||||
|
add(confirmGlow);
|
||||||
|
|
||||||
|
add(confirmTextGlow);
|
||||||
|
|
||||||
|
add(backingTextYeah);
|
||||||
|
|
||||||
|
cardGlow.blend = BlendMode.ADD;
|
||||||
|
cardGlow.visible = false;
|
||||||
|
|
||||||
|
moreWays.visible = false;
|
||||||
|
funnyScroll.visible = false;
|
||||||
|
txtNuts.visible = false;
|
||||||
|
funnyScroll2.visible = false;
|
||||||
|
moreWays2.visible = false;
|
||||||
|
funnyScroll3.visible = false;
|
||||||
|
|
||||||
|
moreWays.funnyColor = 0xFFFFF383;
|
||||||
|
moreWays.speed = 6.8;
|
||||||
|
add(moreWays);
|
||||||
|
|
||||||
|
funnyScroll.funnyColor = 0xFFFF9963;
|
||||||
|
funnyScroll.speed = -3.8;
|
||||||
|
add(funnyScroll);
|
||||||
|
|
||||||
|
txtNuts.speed = 3.5;
|
||||||
|
add(txtNuts);
|
||||||
|
|
||||||
|
funnyScroll2.funnyColor = 0xFFFF9963;
|
||||||
|
funnyScroll2.speed = -3.8;
|
||||||
|
add(funnyScroll2);
|
||||||
|
|
||||||
|
moreWays2.funnyColor = 0xFFFFF383;
|
||||||
|
moreWays2.speed = 6.8;
|
||||||
|
add(moreWays2);
|
||||||
|
|
||||||
|
funnyScroll3.funnyColor = 0xFFFEA400;
|
||||||
|
funnyScroll3.speed = -3.8;
|
||||||
|
add(funnyScroll3);
|
||||||
|
|
||||||
|
glowDark = new FlxSprite(-300, 330).loadGraphic(Paths.image('freeplay/beatglow'));
|
||||||
|
glowDark.blend = BlendMode.MULTIPLY;
|
||||||
|
add(glowDark);
|
||||||
|
|
||||||
|
glow = new FlxSprite(-300, 330).loadGraphic(Paths.image('freeplay/beatglow'));
|
||||||
|
glow.blend = BlendMode.ADD;
|
||||||
|
add(glow);
|
||||||
|
|
||||||
|
glowDark.visible = false;
|
||||||
|
glow.visible = false;
|
||||||
|
|
||||||
|
add(cardGlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
var beatFreq:Int = 1;
|
||||||
|
var beatFreqList:Array<Int> = [1,2,4,8];
|
||||||
|
|
||||||
|
public override function beatHit():Void {
|
||||||
|
// increases the amount of beats that need to go by to pulse the glow because itd flash like craazy at high bpms.....
|
||||||
|
beatFreq = beatFreqList[Math.floor(Conductor.instance.bpm/140)];
|
||||||
|
|
||||||
|
if(Conductor.instance.currentBeat % beatFreq != 0) return;
|
||||||
|
FlxTween.cancelTweensOf(glow);
|
||||||
|
FlxTween.cancelTweensOf(glowDark);
|
||||||
|
|
||||||
|
glow.alpha = 0.8;
|
||||||
|
FlxTween.tween(glow, {alpha: 0}, 16/24, {ease: FlxEase.quartOut});
|
||||||
|
glowDark.alpha = 0;
|
||||||
|
FlxTween.tween(glowDark, {alpha: 0.6}, 18/24, {ease: FlxEase.quartOut});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function introDone():Void
|
||||||
|
{
|
||||||
|
super.introDone();
|
||||||
|
moreWays.visible = true;
|
||||||
|
funnyScroll.visible = true;
|
||||||
|
txtNuts.visible = true;
|
||||||
|
funnyScroll2.visible = true;
|
||||||
|
moreWays2.visible = true;
|
||||||
|
funnyScroll3.visible = true;
|
||||||
|
// grpTxtScrolls.visible = true;
|
||||||
|
glowDark.visible = true;
|
||||||
|
glow.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function confirm():Void
|
||||||
|
{
|
||||||
|
super.confirm();
|
||||||
|
// FlxTween.color(bgDad, 0.33, 0xFFFFFFFF, 0xFF555555, {ease: FlxEase.quadOut});
|
||||||
|
|
||||||
|
moreWays.visible = false;
|
||||||
|
funnyScroll.visible = false;
|
||||||
|
txtNuts.visible = false;
|
||||||
|
funnyScroll2.visible = false;
|
||||||
|
moreWays2.visible = false;
|
||||||
|
funnyScroll3.visible = false;
|
||||||
|
glowDark.visible = false;
|
||||||
|
glow.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function disappear():Void
|
||||||
|
{
|
||||||
|
super.disappear();
|
||||||
|
|
||||||
|
moreWays.visible = false;
|
||||||
|
funnyScroll.visible = false;
|
||||||
|
txtNuts.visible = false;
|
||||||
|
funnyScroll2.visible = false;
|
||||||
|
moreWays2.visible = false;
|
||||||
|
funnyScroll3.visible = false;
|
||||||
|
glowDark.visible = false;
|
||||||
|
glow.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
278
source/funkin/ui/freeplay/backcards/NewCharacterCard.hx
Normal file
278
source/funkin/ui/freeplay/backcards/NewCharacterCard.hx
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
package funkin.ui.freeplay.backcards;
|
||||||
|
|
||||||
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
|
import flash.display.BitmapData;
|
||||||
|
import flixel.FlxCamera;
|
||||||
|
import flixel.math.FlxMath;
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.group.FlxGroup;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||||
|
import flixel.math.FlxAngle;
|
||||||
|
import flixel.math.FlxPoint;
|
||||||
|
import flixel.text.FlxText;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.util.FlxSpriteUtil;
|
||||||
|
import flixel.util.FlxTimer;
|
||||||
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
|
import funkin.ui.freeplay.charselect.PlayableCharacter;
|
||||||
|
import funkin.ui.MusicBeatSubState;
|
||||||
|
import lime.utils.Assets;
|
||||||
|
import openfl.display.BlendMode;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
import funkin.graphics.shaders.AdjustColorShader;
|
||||||
|
import flixel.addons.display.FlxTiledSprite;
|
||||||
|
import flixel.addons.display.FlxBackdrop;
|
||||||
|
|
||||||
|
class NewCharacterCard extends BackingCard
|
||||||
|
{
|
||||||
|
var confirmAtlas:FlxAtlasSprite;
|
||||||
|
|
||||||
|
var darkBg:FlxSprite;
|
||||||
|
var lightLayer:FlxSprite;
|
||||||
|
var multiply1:FlxSprite;
|
||||||
|
var multiply2:FlxSprite;
|
||||||
|
var lightLayer2:FlxSprite;
|
||||||
|
var lightLayer3:FlxSprite;
|
||||||
|
var yellow:FlxSprite;
|
||||||
|
var multiplyBar:FlxSprite;
|
||||||
|
|
||||||
|
var bruh:FlxSprite;
|
||||||
|
|
||||||
|
public var friendFoe:BGScrollingText;
|
||||||
|
public var newUnlock1:BGScrollingText;
|
||||||
|
public var waiting:BGScrollingText;
|
||||||
|
public var newUnlock2:BGScrollingText;
|
||||||
|
public var friendFoe2:BGScrollingText;
|
||||||
|
public var newUnlock3:BGScrollingText;
|
||||||
|
|
||||||
|
public override function applyExitMovers(?exitMovers:FreeplayState.ExitMoverData, ?exitMoversCharSel:FreeplayState.ExitMoverData):Void
|
||||||
|
{
|
||||||
|
super.applyExitMovers(exitMovers, exitMoversCharSel);
|
||||||
|
if (exitMovers == null || exitMoversCharSel == null) return;
|
||||||
|
exitMovers.set([friendFoe],
|
||||||
|
{
|
||||||
|
x: FlxG.width * 2,
|
||||||
|
speed: 0.4,
|
||||||
|
});
|
||||||
|
exitMovers.set([newUnlock1],
|
||||||
|
{
|
||||||
|
x: -newUnlock1.width * 2,
|
||||||
|
y: newUnlock1.y,
|
||||||
|
speed: 0.4,
|
||||||
|
wait: 0
|
||||||
|
});
|
||||||
|
exitMovers.set([waiting],
|
||||||
|
{
|
||||||
|
x: FlxG.width * 2,
|
||||||
|
speed: 0.4,
|
||||||
|
});
|
||||||
|
exitMovers.set([newUnlock2],
|
||||||
|
{
|
||||||
|
x: -newUnlock2.width * 2,
|
||||||
|
speed: 0.5,
|
||||||
|
});
|
||||||
|
exitMovers.set([friendFoe2],
|
||||||
|
{
|
||||||
|
x: FlxG.width * 2,
|
||||||
|
speed: 0.4
|
||||||
|
});
|
||||||
|
exitMovers.set([newUnlock3],
|
||||||
|
{
|
||||||
|
x: -newUnlock3.width * 2,
|
||||||
|
speed: 0.3
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([friendFoe, newUnlock1, waiting, newUnlock2, friendFoe2, newUnlock3, multiplyBar], {
|
||||||
|
y: -60,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function introDone():Void
|
||||||
|
{
|
||||||
|
// pinkBack.color = 0xFFFFD863;
|
||||||
|
|
||||||
|
darkBg.visible = true;
|
||||||
|
friendFoe.visible = true;
|
||||||
|
newUnlock1.visible = true;
|
||||||
|
waiting.visible = true;
|
||||||
|
newUnlock2.visible = true;
|
||||||
|
friendFoe2.visible = true;
|
||||||
|
newUnlock3.visible = true;
|
||||||
|
multiplyBar.visible = true;
|
||||||
|
lightLayer.visible = true;
|
||||||
|
multiply1.visible = true;
|
||||||
|
multiply2.visible = true;
|
||||||
|
lightLayer2.visible = true;
|
||||||
|
yellow.visible = true;
|
||||||
|
lightLayer3.visible = true;
|
||||||
|
|
||||||
|
cardGlow.visible = true;
|
||||||
|
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function enterCharSel():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(friendFoe, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(newUnlock1, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(waiting, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(newUnlock2, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(friendFoe2, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(newUnlock3, {speed: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function init():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut});
|
||||||
|
add(pinkBack);
|
||||||
|
|
||||||
|
confirmTextGlow.blend = BlendMode.ADD;
|
||||||
|
confirmTextGlow.visible = false;
|
||||||
|
|
||||||
|
confirmGlow.blend = BlendMode.ADD;
|
||||||
|
|
||||||
|
confirmGlow.visible = false;
|
||||||
|
confirmGlow2.visible = false;
|
||||||
|
|
||||||
|
friendFoe = new BGScrollingText(0, 163, "COULD IT BE A NEW FRIEND? OR FOE??", FlxG.width, true, 43);
|
||||||
|
newUnlock1 = new BGScrollingText(-440, 215, 'NEW UNLOCK!', FlxG.width / 2, true, 80);
|
||||||
|
waiting = new BGScrollingText(0, 286, "SOMEONE'S WAITING!", FlxG.width / 2, true, 43);
|
||||||
|
newUnlock2 = new BGScrollingText(-220, 331, 'NEW UNLOCK!', FlxG.width / 2, true, 80);
|
||||||
|
friendFoe2 = new BGScrollingText(0, 402, 'COULD IT BE A NEW FRIEND? OR FOE??', FlxG.width, true, 43);
|
||||||
|
newUnlock3 = new BGScrollingText(0, 458, 'NEW UNLOCK!', FlxG.width / 2, true, 80);
|
||||||
|
|
||||||
|
darkBg = new FlxSprite(0, 0).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/darkback'));
|
||||||
|
add(darkBg);
|
||||||
|
|
||||||
|
friendFoe.funnyColor = 0xFF139376;
|
||||||
|
friendFoe.speed = -4;
|
||||||
|
add(friendFoe);
|
||||||
|
|
||||||
|
newUnlock1.funnyColor = 0xFF99BDF2;
|
||||||
|
newUnlock1.speed = 2;
|
||||||
|
add(newUnlock1);
|
||||||
|
|
||||||
|
waiting.funnyColor = 0xFF40EA84;
|
||||||
|
waiting.speed = -2;
|
||||||
|
add(waiting);
|
||||||
|
|
||||||
|
newUnlock2.funnyColor = 0xFF99BDF2;
|
||||||
|
newUnlock2.speed = 2;
|
||||||
|
add(newUnlock2);
|
||||||
|
|
||||||
|
friendFoe2.funnyColor = 0xFF139376;
|
||||||
|
friendFoe2.speed = -4;
|
||||||
|
add(friendFoe2);
|
||||||
|
|
||||||
|
newUnlock3.funnyColor = 0xFF99BDF2;
|
||||||
|
newUnlock3.speed = 2;
|
||||||
|
add(newUnlock3);
|
||||||
|
|
||||||
|
multiplyBar = new FlxSprite(-10, 440).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/multiplyBar'));
|
||||||
|
multiplyBar.blend = BlendMode.MULTIPLY;
|
||||||
|
add(multiplyBar);
|
||||||
|
|
||||||
|
lightLayer = new FlxSprite(-360, 230).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/orange gradient'));
|
||||||
|
lightLayer.blend = BlendMode.ADD;
|
||||||
|
add(lightLayer);
|
||||||
|
|
||||||
|
multiply1 = new FlxSprite(-15, -125).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/red'));
|
||||||
|
multiply1.blend = BlendMode.MULTIPLY;
|
||||||
|
add(multiply1);
|
||||||
|
|
||||||
|
multiply2 = new FlxSprite(-15, -125).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/red'));
|
||||||
|
multiply2.blend = BlendMode.MULTIPLY;
|
||||||
|
add(multiply2);
|
||||||
|
|
||||||
|
lightLayer2 = new FlxSprite(-360, 230).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/orange gradient'));
|
||||||
|
lightLayer2.blend = BlendMode.ADD;
|
||||||
|
add(lightLayer2);
|
||||||
|
|
||||||
|
yellow = new FlxSprite(0, 0).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/yellow bg piece'));
|
||||||
|
yellow.blend = BlendMode.MULTIPLY;
|
||||||
|
add(yellow);
|
||||||
|
|
||||||
|
lightLayer3 = new FlxSprite(-360, 290).loadGraphic(Paths.image('freeplay/backingCards/newCharacter/red gradient'));
|
||||||
|
lightLayer3.blend = BlendMode.ADD;
|
||||||
|
add(lightLayer3);
|
||||||
|
|
||||||
|
cardGlow.blend = BlendMode.ADD;
|
||||||
|
cardGlow.visible = false;
|
||||||
|
|
||||||
|
add(cardGlow);
|
||||||
|
|
||||||
|
darkBg.visible = false;
|
||||||
|
friendFoe.visible = false;
|
||||||
|
newUnlock1.visible = false;
|
||||||
|
waiting.visible = false;
|
||||||
|
newUnlock2.visible = false;
|
||||||
|
friendFoe2.visible = false;
|
||||||
|
newUnlock3.visible = false;
|
||||||
|
multiplyBar.visible = false;
|
||||||
|
lightLayer.visible = false;
|
||||||
|
multiply1.visible = false;
|
||||||
|
multiply2.visible = false;
|
||||||
|
lightLayer2.visible = false;
|
||||||
|
yellow.visible = false;
|
||||||
|
lightLayer3.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _timer:Float = 0;
|
||||||
|
|
||||||
|
override public function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
_timer += elapsed * 2;
|
||||||
|
var sinTest:Float = (Math.sin(_timer) + 1) / 2;
|
||||||
|
lightLayer.alpha = FlxMath.lerp(0.4, 1, sinTest);
|
||||||
|
lightLayer2.alpha = FlxMath.lerp(0.2, 0.5, sinTest);
|
||||||
|
lightLayer3.alpha = FlxMath.lerp(0.1, 0.7, sinTest);
|
||||||
|
|
||||||
|
multiply1.alpha = FlxMath.lerp(1, 0.21, sinTest);
|
||||||
|
multiply2.alpha = FlxMath.lerp(1, 0.21, sinTest);
|
||||||
|
|
||||||
|
yellow.alpha = FlxMath.lerp(0.2, 0.72, sinTest);
|
||||||
|
|
||||||
|
if (instance != null)
|
||||||
|
{
|
||||||
|
instance.angleMaskShader.extraColor = FlxColor.interpolate(0xFF2E2E46, 0xFF60607B, sinTest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function disappear():Void
|
||||||
|
{
|
||||||
|
FlxTween.color(pinkBack, 0.25, 0xFF05020E, 0xFFFFD0D5, {ease: FlxEase.quadOut});
|
||||||
|
|
||||||
|
darkBg.visible = false;
|
||||||
|
friendFoe.visible = false;
|
||||||
|
newUnlock1.visible = false;
|
||||||
|
waiting.visible = false;
|
||||||
|
newUnlock2.visible = false;
|
||||||
|
friendFoe2.visible = false;
|
||||||
|
newUnlock3.visible = false;
|
||||||
|
multiplyBar.visible = false;
|
||||||
|
lightLayer.visible = false;
|
||||||
|
multiply1.visible = false;
|
||||||
|
multiply2.visible = false;
|
||||||
|
lightLayer2.visible = false;
|
||||||
|
yellow.visible = false;
|
||||||
|
lightLayer3.visible = false;
|
||||||
|
|
||||||
|
cardGlow.visible = true;
|
||||||
|
cardGlow.alpha = 1;
|
||||||
|
cardGlow.scale.set(1, 1);
|
||||||
|
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.25, {ease: FlxEase.sineOut});
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function confirm():Void
|
||||||
|
{
|
||||||
|
// confirmAtlas.visible = true;
|
||||||
|
// confirmAtlas.anim.play("");
|
||||||
|
}
|
||||||
|
}
|
||||||
314
source/funkin/ui/freeplay/backcards/PicoCard.hx
Normal file
314
source/funkin/ui/freeplay/backcards/PicoCard.hx
Normal file
|
|
@ -0,0 +1,314 @@
|
||||||
|
package funkin.ui.freeplay.backcards;
|
||||||
|
|
||||||
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
|
import flash.display.BitmapData;
|
||||||
|
import flixel.FlxCamera;
|
||||||
|
import flixel.math.FlxMath;
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.group.FlxGroup;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||||
|
import flixel.math.FlxAngle;
|
||||||
|
import flixel.math.FlxPoint;
|
||||||
|
import flixel.text.FlxText;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.util.FlxSpriteUtil;
|
||||||
|
import flixel.util.FlxTimer;
|
||||||
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
|
import funkin.ui.freeplay.charselect.PlayableCharacter;
|
||||||
|
import funkin.ui.MusicBeatSubState;
|
||||||
|
import lime.utils.Assets;
|
||||||
|
import openfl.display.BlendMode;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
import funkin.graphics.shaders.AdjustColorShader;
|
||||||
|
import flixel.addons.display.FlxTiledSprite;
|
||||||
|
import flixel.addons.display.FlxBackdrop;
|
||||||
|
|
||||||
|
class PicoCard extends BackingCard
|
||||||
|
{
|
||||||
|
var scrollBack:FlxBackdrop;
|
||||||
|
var scrollLower:FlxBackdrop;
|
||||||
|
var scrollTop:FlxBackdrop;
|
||||||
|
var scrollMiddle:FlxBackdrop;
|
||||||
|
|
||||||
|
var glow:FlxSprite;
|
||||||
|
var glowDark:FlxSprite;
|
||||||
|
var blueBar:FlxSprite;
|
||||||
|
|
||||||
|
var confirmAtlas:FlxAtlasSprite;
|
||||||
|
|
||||||
|
public override function enterCharSel():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(scrollBack.velocity, {x: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(scrollLower.velocity, {x: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(scrollTop.velocity, {x: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
FlxTween.tween(scrollMiddle.velocity, {x: 0}, 0.8, {ease: FlxEase.sineIn});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function applyExitMovers(?exitMovers:FreeplayState.ExitMoverData, ?exitMoversCharSel:FreeplayState.ExitMoverData):Void
|
||||||
|
{
|
||||||
|
super.applyExitMovers(exitMovers, exitMoversCharSel);
|
||||||
|
if (exitMovers == null || exitMoversCharSel == null) return;
|
||||||
|
|
||||||
|
exitMoversCharSel.set([scrollTop],
|
||||||
|
{
|
||||||
|
y: -90,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([scrollMiddle],
|
||||||
|
{
|
||||||
|
y: -80,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([blueBar],
|
||||||
|
{
|
||||||
|
y: -70,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([scrollLower],
|
||||||
|
{
|
||||||
|
y: -60,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
|
||||||
|
exitMoversCharSel.set([scrollBack],
|
||||||
|
{
|
||||||
|
y: -50,
|
||||||
|
speed: 0.8,
|
||||||
|
wait: 0.1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function init():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut});
|
||||||
|
add(pinkBack);
|
||||||
|
|
||||||
|
confirmTextGlow.blend = BlendMode.ADD;
|
||||||
|
confirmTextGlow.visible = false;
|
||||||
|
|
||||||
|
confirmGlow.blend = BlendMode.ADD;
|
||||||
|
|
||||||
|
confirmGlow.visible = false;
|
||||||
|
confirmGlow2.visible = false;
|
||||||
|
|
||||||
|
scrollBack = new FlxBackdrop(Paths.image('freeplay/backingCards/pico/lowerLoop'), X, 20);
|
||||||
|
scrollBack.setPosition(0, 200);
|
||||||
|
scrollBack.flipX = true;
|
||||||
|
scrollBack.alpha = 0.39;
|
||||||
|
scrollBack.velocity.x = 110;
|
||||||
|
add(scrollBack);
|
||||||
|
|
||||||
|
scrollLower = new FlxBackdrop(Paths.image('freeplay/backingCards/pico/lowerLoop'), X, 20);
|
||||||
|
scrollLower.setPosition(0, 406);
|
||||||
|
scrollLower.velocity.x = -110;
|
||||||
|
add(scrollLower);
|
||||||
|
|
||||||
|
blueBar = new FlxSprite(0, 239).loadGraphic(Paths.image('freeplay/backingCards/pico/blueBar'));
|
||||||
|
blueBar.blend = BlendMode.MULTIPLY;
|
||||||
|
blueBar.alpha = 0.4;
|
||||||
|
add(blueBar);
|
||||||
|
|
||||||
|
scrollTop = new FlxBackdrop(null, X, 20);
|
||||||
|
scrollTop.setPosition(0, 80);
|
||||||
|
scrollTop.velocity.x = -220;
|
||||||
|
|
||||||
|
scrollTop.frames = Paths.getSparrowAtlas('freeplay/backingCards/pico/topLoop');
|
||||||
|
scrollTop.animation.addByPrefix('uzi', 'uzi info', 24, false);
|
||||||
|
scrollTop.animation.addByPrefix('sniper', 'sniper info', 24, false);
|
||||||
|
scrollTop.animation.addByPrefix('rocket launcher', 'rocket launcher info', 24, false);
|
||||||
|
scrollTop.animation.addByPrefix('rifle', 'rifle info', 24, false);
|
||||||
|
scrollTop.animation.addByPrefix('base', 'base', 24, false);
|
||||||
|
scrollTop.animation.play('base');
|
||||||
|
|
||||||
|
add(scrollTop);
|
||||||
|
|
||||||
|
scrollMiddle = new FlxBackdrop(Paths.image('freeplay/backingCards/pico/middleLoop'), X, 15);
|
||||||
|
scrollMiddle.setPosition(0, 346);
|
||||||
|
add(scrollMiddle);
|
||||||
|
scrollMiddle.velocity.x = 220;
|
||||||
|
|
||||||
|
glowDark = new FlxSprite(-300, 330).loadGraphic(Paths.image('freeplay/backingCards/pico/glow'));
|
||||||
|
glowDark.blend = BlendMode.MULTIPLY;
|
||||||
|
add(glowDark);
|
||||||
|
|
||||||
|
glow = new FlxSprite(-300, 330).loadGraphic(Paths.image('freeplay/backingCards/pico/glow'));
|
||||||
|
glow.blend = BlendMode.ADD;
|
||||||
|
add(glow);
|
||||||
|
|
||||||
|
blueBar.visible = false;
|
||||||
|
scrollBack.visible = false;
|
||||||
|
scrollLower.visible = false;
|
||||||
|
scrollTop.visible = false;
|
||||||
|
scrollMiddle.visible = false;
|
||||||
|
glow.visible = false;
|
||||||
|
glowDark.visible = false;
|
||||||
|
|
||||||
|
confirmAtlas = new FlxAtlasSprite(5, 55, Paths.animateAtlas("freeplay/backingCards/pico/pico-confirm"));
|
||||||
|
confirmAtlas.visible = false;
|
||||||
|
add(confirmAtlas);
|
||||||
|
|
||||||
|
cardGlow.blend = BlendMode.ADD;
|
||||||
|
cardGlow.visible = false;
|
||||||
|
add(cardGlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function confirm():Void
|
||||||
|
{
|
||||||
|
confirmAtlas.visible = true;
|
||||||
|
confirmAtlas.anim.play("");
|
||||||
|
|
||||||
|
FlxTween.color(instance.bgDad, 10 / 24, 0xFFFFFFFF, 0xFF8A8A8A,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
new FlxTimer().start(10 / 24, function(_) {
|
||||||
|
// shoot
|
||||||
|
FlxTween.color(instance.bgDad, 3 / 24, 0xFF343036, 0xFF696366,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new FlxTimer().start(14 / 24, function(_) {
|
||||||
|
// shoot
|
||||||
|
FlxTween.color(instance.bgDad, 3 / 24, 0xFF27292D, 0xFF686A6F,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new FlxTimer().start(18 / 24, function(_) {
|
||||||
|
// shoot
|
||||||
|
FlxTween.color(instance.bgDad, 3 / 24, 0xFF2D282D, 0xFF676164,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new FlxTimer().start(21 / 24, function(_) {
|
||||||
|
// shoot
|
||||||
|
FlxTween.color(instance.bgDad, 3 / 24, 0xFF29292F, 0xFF62626B,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new FlxTimer().start(24 / 24, function(_) {
|
||||||
|
// shoot
|
||||||
|
FlxTween.color(instance.bgDad, 3 / 24, 0xFF29232C, 0xFF808080,
|
||||||
|
{
|
||||||
|
ease: FlxEase.expoOut,
|
||||||
|
onUpdate: function(_) {
|
||||||
|
instance.angleMaskShader.extraColor = instance.bgDad.color;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var beatFreq:Int = 1;
|
||||||
|
var beatFreqList:Array<Int> = [1,2,4,8];
|
||||||
|
|
||||||
|
public override function beatHit():Void {
|
||||||
|
// increases the amount of beats that need to go by to pulse the glow because itd flash like craazy at high bpms.....
|
||||||
|
beatFreq = beatFreqList[Math.floor(Conductor.instance.bpm/140)];
|
||||||
|
|
||||||
|
if(Conductor.instance.currentBeat % beatFreq != 0) return;
|
||||||
|
FlxTween.cancelTweensOf(glow);
|
||||||
|
FlxTween.cancelTweensOf(glowDark);
|
||||||
|
|
||||||
|
glow.alpha = 1;
|
||||||
|
FlxTween.tween(glow, {alpha: 0}, 16/24, {ease: FlxEase.quartOut});
|
||||||
|
glowDark.alpha = 0;
|
||||||
|
FlxTween.tween(glowDark, {alpha: 1}, 18/24, {ease: FlxEase.quartOut});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function introDone():Void
|
||||||
|
{
|
||||||
|
pinkBack.color = 0xFF98A2F3;
|
||||||
|
|
||||||
|
blueBar.visible = true;
|
||||||
|
scrollBack.visible = true;
|
||||||
|
scrollLower.visible = true;
|
||||||
|
scrollTop.visible = true;
|
||||||
|
scrollMiddle.visible = true;
|
||||||
|
glowDark.visible = true;
|
||||||
|
glow.visible = true;
|
||||||
|
|
||||||
|
cardGlow.visible = true;
|
||||||
|
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function disappear():Void
|
||||||
|
{
|
||||||
|
FlxTween.color(pinkBack, 0.25, 0xFF98A2F3, 0xFFFFD0D5, {ease: FlxEase.quadOut});
|
||||||
|
|
||||||
|
blueBar.visible = false;
|
||||||
|
scrollBack.visible = false;
|
||||||
|
scrollLower.visible = false;
|
||||||
|
scrollTop.visible = false;
|
||||||
|
scrollMiddle.visible = false;
|
||||||
|
glowDark.visible = false;
|
||||||
|
glow.visible = false;
|
||||||
|
|
||||||
|
cardGlow.visible = true;
|
||||||
|
cardGlow.alpha = 1;
|
||||||
|
cardGlow.scale.set(1, 1);
|
||||||
|
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.25, {ease: FlxEase.sineOut});
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
var scrollProgress:Float = Math.abs(scrollTop.x % (scrollTop.frameWidth + 20));
|
||||||
|
|
||||||
|
if (scrollTop.animation.curAnim.finished == true)
|
||||||
|
{
|
||||||
|
if (FlxMath.inBounds(scrollProgress, 500, 700) && scrollTop.animation.curAnim.name != 'sniper')
|
||||||
|
{
|
||||||
|
scrollTop.animation.play('sniper', true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FlxMath.inBounds(scrollProgress, 700, 1300) && scrollTop.animation.curAnim.name != 'rifle')
|
||||||
|
{
|
||||||
|
scrollTop.animation.play('rifle', true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FlxMath.inBounds(scrollProgress, 1450, 2000) && scrollTop.animation.curAnim.name != 'rocket launcher')
|
||||||
|
{
|
||||||
|
scrollTop.animation.play('rocket launcher', true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FlxMath.inBounds(scrollProgress, 0, 300) && scrollTop.animation.curAnim.name != 'uzi')
|
||||||
|
{
|
||||||
|
scrollTop.animation.play('uzi', true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ import funkin.play.scoring.Scoring.ScoringRank;
|
||||||
* An object used to retrieve data about a playable character (also known as "weeks").
|
* An object used to retrieve data about a playable character (also known as "weeks").
|
||||||
* Can be scripted to override each function, for custom behavior.
|
* Can be scripted to override each function, for custom behavior.
|
||||||
*/
|
*/
|
||||||
|
@:nullSafety
|
||||||
class PlayableCharacter implements IRegistryEntry<PlayerData>
|
class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
@ -19,7 +20,7 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
/**
|
/**
|
||||||
* Playable character data as parsed from the JSON file.
|
* Playable character data as parsed from the JSON file.
|
||||||
*/
|
*/
|
||||||
public final _data:PlayerData;
|
public final _data:Null<PlayerData>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id The ID of the JSON file to parse.
|
* @param id The ID of the JSON file to parse.
|
||||||
|
|
@ -41,7 +42,7 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
public function getName():String
|
public function getName():String
|
||||||
{
|
{
|
||||||
// TODO: Maybe add localization support?
|
// TODO: Maybe add localization support?
|
||||||
return _data.name;
|
return _data?.name ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,7 +51,7 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
*/
|
*/
|
||||||
public function getOwnedCharacterIds():Array<String>
|
public function getOwnedCharacterIds():Array<String>
|
||||||
{
|
{
|
||||||
return _data.ownedChars;
|
return _data?.ownedChars ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -59,17 +60,17 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
*/
|
*/
|
||||||
public function shouldShowUnownedChars():Bool
|
public function shouldShowUnownedChars():Bool
|
||||||
{
|
{
|
||||||
return _data.showUnownedChars;
|
return _data?.showUnownedChars ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shouldShowCharacter(id:String):Bool
|
public function shouldShowCharacter(id:String):Bool
|
||||||
{
|
{
|
||||||
if (_data.ownedChars.contains(id))
|
if (getOwnedCharacterIds().contains(id))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_data.showUnownedChars)
|
if (shouldShowUnownedChars())
|
||||||
{
|
{
|
||||||
var result = !PlayerRegistry.instance.isCharacterOwned(id);
|
var result = !PlayerRegistry.instance.isCharacterOwned(id);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -78,19 +79,25 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFreeplayDJData():PlayerFreeplayDJData
|
public function getFreeplayStyleID():String
|
||||||
{
|
{
|
||||||
return _data.freeplayDJ;
|
return _data?.freeplayStyle ?? Constants.DEFAULT_FREEPLAY_STYLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFreeplayDJData():Null<PlayerFreeplayDJData>
|
||||||
|
{
|
||||||
|
return _data?.freeplayDJ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFreeplayDJText(index:Int):String
|
public function getFreeplayDJText(index:Int):String
|
||||||
{
|
{
|
||||||
return _data.freeplayDJ.getFreeplayDJText(index);
|
// Silly little placeholder
|
||||||
|
return _data?.freeplayDJ?.getFreeplayDJText(index) ?? 'GET FREAKY ON A FRIDAY';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCharSelectData():PlayerCharSelectData
|
public function getCharSelectData():Null<PlayerCharSelectData>
|
||||||
{
|
{
|
||||||
return _data.charSelect;
|
return _data?.charSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -99,7 +106,7 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
*/
|
*/
|
||||||
public function getResultsAnimationDatas(rank:ScoringRank):Array<PlayerResultsAnimationData>
|
public function getResultsAnimationDatas(rank:ScoringRank):Array<PlayerResultsAnimationData>
|
||||||
{
|
{
|
||||||
if (_data.results == null)
|
if (_data == null || _data.results == null)
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
@ -119,12 +126,33 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getResultsMusicPath(rank:ScoringRank):String
|
||||||
|
{
|
||||||
|
switch (rank)
|
||||||
|
{
|
||||||
|
case PERFECT_GOLD:
|
||||||
|
return _data?.results?.music?.PERFECT_GOLD ?? "resultsPERFECT";
|
||||||
|
case PERFECT:
|
||||||
|
return _data?.results?.music?.PERFECT ?? "resultsPERFECT";
|
||||||
|
case EXCELLENT:
|
||||||
|
return _data?.results?.music?.EXCELLENT ?? "resultsEXCELLENT";
|
||||||
|
case GREAT:
|
||||||
|
return _data?.results?.music?.GREAT ?? "resultsNORMAL";
|
||||||
|
case GOOD:
|
||||||
|
return _data?.results?.music?.GOOD ?? "resultsNORMAL";
|
||||||
|
case SHIT:
|
||||||
|
return _data?.results?.music?.SHIT ?? "resultsSHIT";
|
||||||
|
default:
|
||||||
|
return _data?.results?.music?.GOOD ?? "resultsNORMAL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this character is unlocked.
|
* Returns whether this character is unlocked.
|
||||||
*/
|
*/
|
||||||
public function isUnlocked():Bool
|
public function isUnlocked():Bool
|
||||||
{
|
{
|
||||||
return _data.unlocked;
|
return _data?.unlocked ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,17 @@ class MainMenuState extends MusicBeatState
|
||||||
FlxTransitionableState.skipNextTransIn = true;
|
FlxTransitionableState.skipNextTransIn = true;
|
||||||
FlxTransitionableState.skipNextTransOut = true;
|
FlxTransitionableState.skipNextTransOut = true;
|
||||||
|
|
||||||
openSubState(new FreeplayState());
|
#if FEATURE_DEBUG_FUNCTIONS
|
||||||
|
// Debug function: Hold SHIFT when selecting Freeplay to swap character without the char select menu
|
||||||
|
var targetCharacter:Null<String> = (FlxG.keys.pressed.SHIFT) ? (FreeplayState.rememberedCharacterId == "pico" ? "bf" : "pico") : null;
|
||||||
|
#else
|
||||||
|
var targetCharacter:Null<String> = null;
|
||||||
|
#end
|
||||||
|
|
||||||
|
openSubState(new FreeplayState(
|
||||||
|
{
|
||||||
|
character: targetCharacter
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
#if CAN_OPEN_LINKS
|
#if CAN_OPEN_LINKS
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,11 @@ class Constants
|
||||||
*/
|
*/
|
||||||
public static final DEFAULT_NOTE_STYLE:String = 'funkin';
|
public static final DEFAULT_NOTE_STYLE:String = 'funkin';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default freeplay style for characters.
|
||||||
|
*/
|
||||||
|
public static final DEFAULT_FREEPLAY_STYLE:String = 'bf';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default pixel note style for songs.
|
* The default pixel note style for songs.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -33,4 +33,19 @@ class ReflectUtil
|
||||||
{
|
{
|
||||||
return Type.getClassName(Type.getClass(obj));
|
return Type.getClassName(Type.getClass(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getAnonymousFieldsOf(obj:Dynamic):Array<String>
|
||||||
|
{
|
||||||
|
return Reflect.fields(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAnonymousField(obj:Dynamic, name:String):Dynamic
|
||||||
|
{
|
||||||
|
return Reflect.field(obj, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function hasAnonymousField(obj:Dynamic, name:String):Bool
|
||||||
|
{
|
||||||
|
return Reflect.hasField(obj, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue