mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-11-15 11:22:55 +00:00
Fixes for scripted song events, define vocal tracks per variation, display suffixed difficulties properly.
This commit is contained in:
parent
3db0cf3e0a
commit
f3624f7e76
|
@ -46,7 +46,7 @@ class SongEventRegistry
|
|||
|
||||
if (event != null)
|
||||
{
|
||||
trace(' Loaded built-in song event: (${event.id})');
|
||||
trace(' Loaded built-in song event: ${event.id}');
|
||||
eventCache.set(event.id, event);
|
||||
}
|
||||
else
|
||||
|
@ -59,9 +59,9 @@ class SongEventRegistry
|
|||
static function registerScriptedEvents()
|
||||
{
|
||||
var scriptedEventClassNames:Array<String> = ScriptedSongEvent.listScriptClasses();
|
||||
trace('Instantiating ${scriptedEventClassNames.length} scripted song events...');
|
||||
if (scriptedEventClassNames == null || scriptedEventClassNames.length == 0) return;
|
||||
|
||||
trace('Instantiating ${scriptedEventClassNames.length} scripted song events...');
|
||||
for (eventCls in scriptedEventClassNames)
|
||||
{
|
||||
var event:SongEvent = ScriptedSongEvent.init(eventCls, "UKNOWN");
|
||||
|
|
|
@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.2.4]
|
||||
### Added
|
||||
- Added `playData.characters.opponentVocals` to specify which vocal track(s) to play 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.
|
||||
- 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)
|
||||
|
||||
## [2.2.3]
|
||||
### Added
|
||||
- Added `charter` field to denote authorship of a chart.
|
||||
|
|
|
@ -529,12 +529,26 @@ class SongCharacterData implements ICloneable<SongCharacterData>
|
|||
@:default([])
|
||||
public var altInstrumentals:Array<String> = [];
|
||||
|
||||
public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '')
|
||||
@:optional
|
||||
public var opponentVocals:Null<Array<String>> = null;
|
||||
|
||||
@:optional
|
||||
public var playerVocals:Null<Array<String>> = null;
|
||||
|
||||
public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '', ?altInstrumentals:Array<String>,
|
||||
?opponentVocals:Array<String>, ?playerVocals:Array<String>)
|
||||
{
|
||||
this.player = player;
|
||||
this.girlfriend = girlfriend;
|
||||
this.opponent = opponent;
|
||||
this.instrumental = instrumental;
|
||||
|
||||
this.altInstrumentals = altInstrumentals;
|
||||
this.opponentVocals = opponentVocals;
|
||||
this.playerVocals = playerVocals;
|
||||
|
||||
if (opponentVocals == null) this.opponentVocals = [opponent];
|
||||
if (playerVocals == null) this.playerVocals = [player];
|
||||
}
|
||||
|
||||
public function clone():SongCharacterData
|
||||
|
@ -722,18 +736,6 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
|
|||
{
|
||||
return new SongEventDataRaw(this.time, this.eventKind, this.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap SongEventData in an abstract so we can overload operators.
|
||||
*/
|
||||
@:forward(time, eventKind, value, activated, getStepTime, clone)
|
||||
abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw
|
||||
{
|
||||
public function new(time:Float, eventKind:String, value:Dynamic = null)
|
||||
{
|
||||
this = new SongEventDataRaw(time, eventKind, value);
|
||||
}
|
||||
|
||||
public function valueAsStruct(?defaultKey:String = "key"):Dynamic
|
||||
{
|
||||
|
@ -757,27 +759,27 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
|||
}
|
||||
}
|
||||
|
||||
public inline function getHandler():Null<SongEvent>
|
||||
public function getHandler():Null<SongEvent>
|
||||
{
|
||||
return SongEventRegistry.getEvent(this.eventKind);
|
||||
}
|
||||
|
||||
public inline function getSchema():Null<SongEventSchema>
|
||||
public function getSchema():Null<SongEventSchema>
|
||||
{
|
||||
return SongEventRegistry.getEventSchema(this.eventKind);
|
||||
}
|
||||
|
||||
public inline function getDynamic(key:String):Null<Dynamic>
|
||||
public function getDynamic(key:String):Null<Dynamic>
|
||||
{
|
||||
return this.value == null ? null : Reflect.field(this.value, key);
|
||||
}
|
||||
|
||||
public inline function getBool(key:String):Null<Bool>
|
||||
public function getBool(key:String):Null<Bool>
|
||||
{
|
||||
return this.value == null ? null : cast Reflect.field(this.value, key);
|
||||
}
|
||||
|
||||
public inline function getInt(key:String):Null<Int>
|
||||
public function getInt(key:String):Null<Int>
|
||||
{
|
||||
if (this.value == null) return null;
|
||||
var result = Reflect.field(this.value, key);
|
||||
|
@ -787,7 +789,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
|||
return cast result;
|
||||
}
|
||||
|
||||
public inline function getFloat(key:String):Null<Float>
|
||||
public function getFloat(key:String):Null<Float>
|
||||
{
|
||||
if (this.value == null) return null;
|
||||
var result = Reflect.field(this.value, key);
|
||||
|
@ -797,17 +799,17 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
|||
return cast result;
|
||||
}
|
||||
|
||||
public inline function getString(key:String):String
|
||||
public function getString(key:String):String
|
||||
{
|
||||
return this.value == null ? null : cast Reflect.field(this.value, key);
|
||||
}
|
||||
|
||||
public inline function getArray(key:String):Array<Dynamic>
|
||||
public function getArray(key:String):Array<Dynamic>
|
||||
{
|
||||
return this.value == null ? null : cast Reflect.field(this.value, key);
|
||||
}
|
||||
|
||||
public inline function getBoolArray(key:String):Array<Bool>
|
||||
public function getBoolArray(key:String):Array<Bool>
|
||||
{
|
||||
return this.value == null ? null : cast Reflect.field(this.value, key);
|
||||
}
|
||||
|
@ -839,6 +841,19 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
|||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap SongEventData in an abstract so we can overload operators.
|
||||
*/
|
||||
@:forward(time, eventKind, value, activated, getStepTime, clone, getHandler, getSchema, getDynamic, getBool, getInt, getFloat, getString, getArray,
|
||||
getBoolArray, buildTooltip, valueAsStruct)
|
||||
abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw
|
||||
{
|
||||
public function new(time:Float, eventKind:String, value:Dynamic = null)
|
||||
{
|
||||
this = new SongEventDataRaw(time, eventKind, value);
|
||||
}
|
||||
|
||||
public function clone():SongEventData
|
||||
{
|
||||
|
|
|
@ -234,6 +234,8 @@ class PolymodHandler
|
|||
// NOTE: Scripted classes are automatically aliased to their parent class.
|
||||
Polymod.addImportAlias('flixel.math.FlxPoint', flixel.math.FlxPoint.FlxBasePoint);
|
||||
|
||||
Polymod.addImportAlias('funkin.data.event.SongEventSchema', funkin.data.event.SongEventSchema.SongEventSchemaRaw);
|
||||
|
||||
// Add blacklisting for prohibited classes and packages.
|
||||
|
||||
// `Sys`
|
||||
|
|
|
@ -580,6 +580,8 @@ class PlayState extends MusicBeatSubState
|
|||
// TODO: Refactor or document
|
||||
var generatedMusic:Bool = false;
|
||||
|
||||
var skipEndingTransition:Bool = false;
|
||||
|
||||
static final BACKGROUND_COLOR:FlxColor = FlxColor.BLACK;
|
||||
|
||||
/**
|
||||
|
@ -1926,7 +1928,9 @@ class PlayState extends MusicBeatSubState
|
|||
return;
|
||||
}
|
||||
|
||||
FlxG.sound.music.onComplete = endSong.bind(false);
|
||||
FlxG.sound.music.onComplete = function() {
|
||||
endSong(skipEndingTransition);
|
||||
};
|
||||
// A negative instrumental offset means the song skips the first few milliseconds of the track.
|
||||
// This just gets added into the startTimestamp behavior so we don't need to do anything extra.
|
||||
FlxG.sound.music.play(true, startTimestamp - Conductor.instance.instrumentalOffset);
|
||||
|
@ -1965,7 +1969,7 @@ class PlayState extends MusicBeatSubState
|
|||
if (vocals == null) return;
|
||||
|
||||
// Skip this if the music is paused (GameOver, Pause menu, start-of-song offset, etc.)
|
||||
if (!FlxG.sound.music.playing) return;
|
||||
if (!(FlxG?.sound?.music?.playing ?? false)) return;
|
||||
|
||||
vocals.pause();
|
||||
|
||||
|
|
|
@ -494,6 +494,24 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
return diffFiltered;
|
||||
}
|
||||
|
||||
public function listSuffixedDifficulties(variationIds:Array<String>, ?showLocked:Bool, ?showHidden:Bool):Array<String>
|
||||
{
|
||||
var result = [];
|
||||
|
||||
for (variation in variationIds)
|
||||
{
|
||||
var difficulties = listDifficulties(variation, null, showLocked, showHidden);
|
||||
for (difficulty in difficulties)
|
||||
{
|
||||
var suffixedDifficulty = (variation != Constants.DEFAULT_VARIATION
|
||||
&& variation != 'erect') ? '$difficulty-${variation}' : difficulty;
|
||||
result.push(suffixedDifficulty);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public function hasDifficulty(diffId:String, ?variationId:String, ?variationIds:Array<String>):Bool
|
||||
{
|
||||
if (variationIds == null) variationIds = [];
|
||||
|
@ -706,10 +724,11 @@ class SongDifficulty
|
|||
* Cache the vocals for a given character.
|
||||
* @param id The character we are about to play.
|
||||
*/
|
||||
public inline function cacheVocals():Void
|
||||
public function cacheVocals():Void
|
||||
{
|
||||
for (voice in buildVoiceList())
|
||||
{
|
||||
trace('Caching vocal track: $voice');
|
||||
FlxG.sound.cache(voice);
|
||||
}
|
||||
}
|
||||
|
@ -721,6 +740,20 @@ class SongDifficulty
|
|||
* @param id The character we are about to play.
|
||||
*/
|
||||
public function buildVoiceList():Array<String>
|
||||
{
|
||||
var result:Array<String> = [];
|
||||
result = result.concat(buildPlayerVoiceList());
|
||||
result = result.concat(buildOpponentVoiceList());
|
||||
if (result.length == 0)
|
||||
{
|
||||
var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : '';
|
||||
// Try to use `Voices.ogg` if no other voices are found.
|
||||
if (Assets.exists(Paths.voices(this.song.id, ''))) result.push(Paths.voices(this.song.id, '$suffix'));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public function buildPlayerVoiceList():Array<String>
|
||||
{
|
||||
var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : '';
|
||||
|
||||
|
@ -728,62 +761,88 @@ class SongDifficulty
|
|||
// For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`.
|
||||
// Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`.
|
||||
|
||||
if (characters.playerVocals == null)
|
||||
{
|
||||
var playerId:String = characters.player;
|
||||
var voicePlayer:String = Paths.voices(this.song.id, '-$playerId$suffix');
|
||||
while (voicePlayer != null && !Assets.exists(voicePlayer))
|
||||
var playerVoice:String = Paths.voices(this.song.id, '-${playerId}$suffix');
|
||||
|
||||
while (playerVoice != null && !Assets.exists(playerVoice))
|
||||
{
|
||||
// Remove the last suffix.
|
||||
// For example, bf-car becomes bf.
|
||||
playerId = playerId.split('-').slice(0, -1).join('-');
|
||||
// Try again.
|
||||
voicePlayer = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix');
|
||||
playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix');
|
||||
}
|
||||
if (voicePlayer == null)
|
||||
if (playerVoice == null)
|
||||
{
|
||||
// Try again without $suffix.
|
||||
playerId = characters.player;
|
||||
voicePlayer = Paths.voices(this.song.id, '-${playerId}');
|
||||
while (voicePlayer != null && !Assets.exists(voicePlayer))
|
||||
playerVoice = Paths.voices(this.song.id, '-${playerId}');
|
||||
while (playerVoice != null && !Assets.exists(playerVoice))
|
||||
{
|
||||
// Remove the last suffix.
|
||||
playerId = playerId.split('-').slice(0, -1).join('-');
|
||||
// Try again.
|
||||
voicePlayer = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix');
|
||||
playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix');
|
||||
}
|
||||
}
|
||||
|
||||
return playerVoice != null ? [playerVoice] : [];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The metadata explicitly defines the list of voices.
|
||||
var playerIds:Array<String> = characters?.playerVocals ?? [characters.player];
|
||||
var playerVoices:Array<String> = playerIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix'));
|
||||
|
||||
return playerVoices;
|
||||
}
|
||||
}
|
||||
|
||||
public function buildOpponentVoiceList():Array<String>
|
||||
{
|
||||
var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : '';
|
||||
|
||||
// Automatically resolve voices by removing suffixes.
|
||||
// For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`.
|
||||
// Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`.
|
||||
|
||||
if (characters.opponentVocals == null)
|
||||
{
|
||||
var opponentId:String = characters.opponent;
|
||||
var voiceOpponent:String = Paths.voices(this.song.id, '-${opponentId}$suffix');
|
||||
while (voiceOpponent != null && !Assets.exists(voiceOpponent))
|
||||
var opponentVoice:String = Paths.voices(this.song.id, '-${opponentId}$suffix');
|
||||
while (opponentVoice != null && !Assets.exists(opponentVoice))
|
||||
{
|
||||
// Remove the last suffix.
|
||||
opponentId = opponentId.split('-').slice(0, -1).join('-');
|
||||
// Try again.
|
||||
voiceOpponent = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix');
|
||||
opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix');
|
||||
}
|
||||
if (voiceOpponent == null)
|
||||
if (opponentVoice == null)
|
||||
{
|
||||
// Try again without $suffix.
|
||||
opponentId = characters.opponent;
|
||||
voiceOpponent = Paths.voices(this.song.id, '-${opponentId}');
|
||||
while (voiceOpponent != null && !Assets.exists(voiceOpponent))
|
||||
opponentVoice = Paths.voices(this.song.id, '-${opponentId}');
|
||||
while (opponentVoice != null && !Assets.exists(opponentVoice))
|
||||
{
|
||||
// Remove the last suffix.
|
||||
opponentId = opponentId.split('-').slice(0, -1).join('-');
|
||||
// Try again.
|
||||
voiceOpponent = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix');
|
||||
opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix');
|
||||
}
|
||||
}
|
||||
|
||||
var result:Array<String> = [];
|
||||
if (voicePlayer != null) result.push(voicePlayer);
|
||||
if (voiceOpponent != null) result.push(voiceOpponent);
|
||||
if (voicePlayer == null && voiceOpponent == null)
|
||||
{
|
||||
// Try to use `Voices.ogg` if no other voices are found.
|
||||
if (Assets.exists(Paths.voices(this.song.id, ''))) result.push(Paths.voices(this.song.id, '$suffix'));
|
||||
return opponentVoice != null ? [opponentVoice] : [];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The metadata explicitly defines the list of voices.
|
||||
var opponentIds:Array<String> = characters?.opponentVocals ?? [characters.opponent];
|
||||
var opponentVoices:Array<String> = opponentIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix'));
|
||||
|
||||
return opponentVoices;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -795,26 +854,19 @@ class SongDifficulty
|
|||
{
|
||||
var result:VoicesGroup = new VoicesGroup();
|
||||
|
||||
var voiceList:Array<String> = buildVoiceList();
|
||||
|
||||
if (voiceList.length == 0)
|
||||
{
|
||||
trace('Could not find any voices for song ${this.song.id}');
|
||||
return result;
|
||||
}
|
||||
var playerVoiceList:Array<String> = this.buildPlayerVoiceList();
|
||||
var opponentVoiceList:Array<String> = this.buildOpponentVoiceList();
|
||||
|
||||
// Add player vocals.
|
||||
if (voiceList[0] != null) result.addPlayerVoice(FunkinSound.load(voiceList[0]));
|
||||
// Add opponent vocals.
|
||||
if (voiceList[1] != null) result.addOpponentVoice(FunkinSound.load(voiceList[1]));
|
||||
|
||||
// Add additional vocals.
|
||||
if (voiceList.length > 2)
|
||||
for (playerVoice in playerVoiceList)
|
||||
{
|
||||
for (i in 2...voiceList.length)
|
||||
{
|
||||
result.add(FunkinSound.load(Assets.getSound(voiceList[i])));
|
||||
result.addPlayerVoice(FunkinSound.load(playerVoice));
|
||||
}
|
||||
|
||||
// Add opponent vocals.
|
||||
for (opponentVoice in opponentVoiceList)
|
||||
{
|
||||
result.addOpponentVoice(FunkinSound.load(opponentVoice));
|
||||
}
|
||||
|
||||
result.playerVoicesOffset = offsets.getVocalOffset(characters.player);
|
||||
|
|
|
@ -339,7 +339,7 @@ class FreeplayState extends MusicBeatSubState
|
|||
// Only display songs which actually have available difficulties for the current character.
|
||||
var displayedVariations = song.getVariationsByCharacter(currentCharacter);
|
||||
trace('Displayed Variations (${songId}): $displayedVariations');
|
||||
var availableDifficultiesForSong:Array<String> = song.listDifficulties(displayedVariations, false);
|
||||
var availableDifficultiesForSong:Array<String> = song.listSuffixedDifficulties(displayedVariations, false, false);
|
||||
trace('Available Difficulties: $availableDifficultiesForSong');
|
||||
if (availableDifficultiesForSong.length == 0) continue;
|
||||
|
||||
|
@ -1120,7 +1120,7 @@ class FreeplayState extends MusicBeatSubState
|
|||
|
||||
// NOW we can interact with the menu
|
||||
busy = false;
|
||||
grpCapsules.members[curSelected].sparkle.alpha = 0.7;
|
||||
capsule.sparkle.alpha = 0.7;
|
||||
playCurSongPreview(capsule);
|
||||
}, null);
|
||||
|
||||
|
@ -1674,6 +1674,9 @@ class FreeplayState extends MusicBeatSubState
|
|||
songCapsule.init(null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the song preview in case we changed variations (normal->erect etc)
|
||||
playCurSongPreview();
|
||||
}
|
||||
|
||||
// Set the album graphic and play the animation if relevant.
|
||||
|
@ -1912,8 +1915,10 @@ class FreeplayState extends MusicBeatSubState
|
|||
}
|
||||
}
|
||||
|
||||
public function playCurSongPreview(daSongCapsule:SongMenuItem):Void
|
||||
public function playCurSongPreview(?daSongCapsule:SongMenuItem):Void
|
||||
{
|
||||
if (daSongCapsule == null) daSongCapsule = grpCapsules.members[curSelected];
|
||||
|
||||
if (curSelected == 0)
|
||||
{
|
||||
FunkinSound.playMusic('freeplayRandom',
|
||||
|
@ -2145,7 +2150,7 @@ class FreeplaySongData
|
|||
|
||||
function updateValues(variations:Array<String>):Void
|
||||
{
|
||||
this.songDifficulties = song.listDifficulties(null, variations, false, false);
|
||||
this.songDifficulties = song.listSuffixedDifficulties(variations, false, false);
|
||||
if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY;
|
||||
|
||||
var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, null, variations);
|
||||
|
@ -2207,15 +2212,26 @@ class DifficultySprite extends FlxSprite
|
|||
|
||||
difficultyId = diffId;
|
||||
|
||||
if (Assets.exists(Paths.file('images/freeplay/freeplay${diffId}.xml')))
|
||||
var assetDiffId:String = diffId;
|
||||
while (!Assets.exists(Paths.image('freeplay/freeplay${assetDiffId}')))
|
||||
{
|
||||
this.frames = Paths.getSparrowAtlas('freeplay/freeplay${diffId}');
|
||||
// Remove the last suffix of the difficulty id until we find an asset or there are no more suffixes.
|
||||
var assetDiffIdParts:Array<String> = assetDiffId.split('-');
|
||||
assetDiffIdParts.pop();
|
||||
if (assetDiffIdParts.length == 0) break;
|
||||
assetDiffId = assetDiffIdParts.join('-');
|
||||
}
|
||||
|
||||
// Check for an XML to use an animation instead of an image.
|
||||
if (Assets.exists(Paths.file('images/freeplay/freeplay${assetDiffId}.xml')))
|
||||
{
|
||||
this.frames = Paths.getSparrowAtlas('freeplay/freeplay${assetDiffId}');
|
||||
this.animation.addByPrefix('idle', 'idle0', 24, true);
|
||||
if (Preferences.flashingLights) this.animation.play('idle');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.loadGraphic(Paths.image('freeplay/freeplay' + diffId));
|
||||
this.loadGraphic(Paths.image('freeplay/freeplay' + assetDiffId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ class SongMenuItem extends FlxSpriteGroup
|
|||
|
||||
sparkle = new FlxSprite(ranking.x, ranking.y);
|
||||
sparkle.frames = Paths.getSparrowAtlas('freeplay/sparkle');
|
||||
sparkle.animation.addByPrefix('sparkle', 'sparkle', 24, false);
|
||||
sparkle.animation.addByPrefix('sparkle', 'sparkle Export0', 24, false);
|
||||
sparkle.animation.play('sparkle', true);
|
||||
sparkle.scale.set(0.8, 0.8);
|
||||
sparkle.blend = BlendMode.ADD;
|
||||
|
@ -523,7 +523,6 @@ class SongMenuItem extends FlxSpriteGroup
|
|||
checkWeek(songData?.songId);
|
||||
}
|
||||
|
||||
|
||||
var frameInTicker:Float = 0;
|
||||
var frameInTypeBeat:Int = 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue