1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-09-12 05:07:06 +00:00

Merge remote-tracking branch 'origin/rewrite/master' into rewrite/feature/chart-editor-erect-template

This commit is contained in:
EliteMasterEric 2023-10-10 23:46:54 -04:00
commit 1ccb84bbf2
21 changed files with 1420 additions and 309 deletions

3
.gitignore vendored
View file

@ -3,4 +3,5 @@
APIStuff.hx
dump/
export/
RECOVER_*.fla
RECOVER_*.fla
shitAudio/

View file

@ -32,7 +32,7 @@
"name": "flxanimate",
"type": "git",
"dir": null,
"ref": "a9136359271cae6ea3016b7fd9023c5c42562933",
"ref": "dd2903f7dc7024335b981edf2a770760cec912e1",
"url": "https://github.com/ninjamuffin99/flxanimate"
},
{

View file

@ -1,5 +1,6 @@
package funkin;
import funkin.shaderslmfao.HSVShader;
import funkin.ui.StickerSubState;
import flash.text.TextField;
import flixel.FlxCamera;
@ -12,6 +13,7 @@ import flixel.addons.ui.FlxInputText;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.group.FlxGroup;
import flixel.group.FlxSpriteGroup;
import flixel.system.debug.watch.Tracker.TrackerProfile;
import flixel.input.touch.FlxTouch;
import flixel.math.FlxAngle;
import flixel.math.FlxMath;
@ -21,6 +23,7 @@ import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import funkin.data.song.SongRegistry;
import funkin.data.level.LevelRegistry;
import flixel.util.FlxSpriteUtil;
import flixel.util.FlxTimer;
import funkin.Controls.Control;
@ -29,6 +32,7 @@ import funkin.freeplayStuff.DJBoyfriend;
import funkin.freeplayStuff.FreeplayScore;
import funkin.freeplayStuff.LetterSort;
import funkin.freeplayStuff.SongMenuItem;
import funkin.freeplayStuff.DifficultyStars;
import funkin.play.HealthIcon;
import funkin.play.PlayState;
import funkin.shaderslmfao.AngleMask;
@ -38,6 +42,7 @@ import funkin.play.PlayStatePlaylist;
import funkin.play.song.Song;
import lime.app.Future;
import lime.utils.Assets;
import funkin.graphics.adobeanimate.FlxAtlasSprite;
class FreeplayState extends MusicBeatSubState
{
@ -69,6 +74,7 @@ class FreeplayState extends MusicBeatSubState
var grpSongs:FlxTypedGroup<Alphabet>;
var grpCapsules:FlxTypedGroup<SongMenuItem>;
var curCapsule:SongMenuItem;
var curPlaying:Bool = false;
var dj:DJBoyfriend;
@ -114,44 +120,33 @@ class FreeplayState extends MusicBeatSubState
#if debug
isDebug = true;
addSong('Test', 'tutorial', 'bf-pixel');
addSong('Pyro', 'weekend1', 'darnell');
// addSong('Test', 'tutorial', 'bf-pixel');
// addSong('Pyro', 'weekend1', 'darnell');
#end
var initSonglist = CoolUtil.coolTextFile(Paths.txt('freeplaySonglist'));
// var initSonglist = CoolUtil.coolTextFile(Paths.txt('freeplaySonglist'));
for (i in 0...initSonglist.length)
{
songs.push(new FreeplaySongData(initSonglist[i], 'tutorial', 'gf'));
}
// for (i in 0...initSonglist.length)
// {
// songs.push(new FreeplaySongData(initSonglist[i], 'tutorial', 'gf'));
// }
if (FlxG.sound.music != null)
{
if (!FlxG.sound.music.playing) FlxG.sound.playMusic(Paths.music('freakyMenu/freakyMenu'));
}
// if (StoryMenuState.weekUnlocked[2] || isDebug)
addWeek(['Bopeebo', 'Fresh', 'Dadbattle'], 'week1', ['dad']);
// if (StoryMenuState.weekUnlocked[2] || isDebug)
addWeek(['Spookeez', 'South', 'Monster'], 'week2', ['spooky', 'spooky', 'monster']);
// if (StoryMenuState.weekUnlocked[3] || isDebug)
addWeek(['Pico', 'Philly-Nice', 'Blammed'], 'week3', ['pico']);
// if (StoryMenuState.weekUnlocked[4] || isDebug)
addWeek(['Satin-Panties', 'High', 'MILF'], 'week4', ['mom']);
// if (StoryMenuState.weekUnlocked[5] || isDebug)
addWeek(['Cocoa', 'Eggnog', 'Winter-Horrorland'], 'week5', ['parents-christmas', 'parents-christmas', 'monster-christmas']);
// if (StoryMenuState.weekUnlocked[6] || isDebug)
addWeek(['Senpai', 'Roses', 'Thorns'], 'week6', ['senpai', 'senpai', 'spirit']);
// if (StoryMenuState.weekUnlocked[7] || isDebug)
addWeek(['Ugh', 'Guns', 'Stress'], 'week7', ['tankman']);
addWeek(["Darnell", "lit-up", "2hot", "blazin"], 'weekend1', ['darnell']);
// programmatically adds the songs via LevelRegistry and SongRegistry
for (coolWeek in LevelRegistry.instance.listBaseGameLevelIds())
{
for (coolSong in LevelRegistry.instance.parseEntryData(coolWeek).songs)
{
var metadata = SongRegistry.instance.parseEntryMetadata(coolSong);
var char = metadata.playData.characters.opponent;
var songName = metadata.songName;
addSong(songName, coolWeek, char);
}
}
// LOAD MUSIC
@ -169,7 +164,7 @@ class FreeplayState extends MusicBeatSubState
FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut});
add(pinkBack);
var orangeBackShit:FlxSprite = new FlxSprite(84, FlxG.height * 0.68).makeGraphic(Std.int(pinkBack.width), 50, 0xFFffd400);
var orangeBackShit:FlxSprite = new FlxSprite(84, 440).makeGraphic(Std.int(pinkBack.width), 75, 0xFFfeda00);
add(orangeBackShit);
var alsoOrangeLOL:FlxSprite = new FlxSprite(0, orangeBackShit.y).makeGraphic(100, Std.int(orangeBackShit.height), 0xFFffd400);
@ -191,9 +186,11 @@ class FreeplayState extends MusicBeatSubState
add(grpTxtScrolls);
grpTxtScrolls.visible = false;
var moreWays:BGScrollingText = new BGScrollingText(0, 200, "HOT BLOODED IN MORE WAYS THAN ONE", FlxG.width);
FlxG.debugger.addTrackerProfile(new TrackerProfile(BGScrollingText, ["x", "y", "speed", "size"]));
var moreWays:BGScrollingText = new BGScrollingText(0, 160, "HOT BLOODED IN MORE WAYS THAN ONE", FlxG.width, true, 43);
moreWays.funnyColor = 0xFFfff383;
moreWays.speed = 4;
moreWays.speed = 6.8;
grpTxtScrolls.add(moreWays);
exitMovers.set([moreWays],
@ -202,9 +199,9 @@ class FreeplayState extends MusicBeatSubState
speed: 0.4,
});
var funnyScroll:BGScrollingText = new BGScrollingText(0, 250, "BOYFRIEND", FlxG.width / 2);
var funnyScroll:BGScrollingText = new BGScrollingText(0, 220, "BOYFRIEND", FlxG.width / 2, false, 60);
funnyScroll.funnyColor = 0xFFff9963;
funnyScroll.speed = -1;
funnyScroll.speed = -3.8;
grpTxtScrolls.add(funnyScroll);
exitMovers.set([funnyScroll],
@ -215,7 +212,8 @@ class FreeplayState extends MusicBeatSubState
wait: 0
});
var txtNuts:BGScrollingText = new BGScrollingText(0, 300, "PROTECT YO NUTS", FlxG.width / 2);
var txtNuts:BGScrollingText = new BGScrollingText(0, 285, "PROTECT YO NUTS", FlxG.width / 2, true, 43);
txtNuts.speed = 3.5;
grpTxtScrolls.add(txtNuts);
exitMovers.set([txtNuts],
{
@ -223,9 +221,9 @@ class FreeplayState extends MusicBeatSubState
speed: 0.4,
});
var funnyScroll2:BGScrollingText = new BGScrollingText(0, 340, "BOYFRIEND", FlxG.width / 2);
var funnyScroll2:BGScrollingText = new BGScrollingText(0, 335, "BOYFRIEND", FlxG.width / 2, false, 60);
funnyScroll2.funnyColor = 0xFFff9963;
funnyScroll2.speed = -1.2;
funnyScroll2.speed = -3.8;
grpTxtScrolls.add(funnyScroll2);
exitMovers.set([funnyScroll2],
@ -234,9 +232,9 @@ class FreeplayState extends MusicBeatSubState
speed: 0.5,
});
var moreWays2:BGScrollingText = new BGScrollingText(0, 400, "HOT BLOODED IN MORE WAYS THAN ONE", FlxG.width);
var moreWays2:BGScrollingText = new BGScrollingText(0, 397, "HOT BLOODED IN MORE WAYS THAN ONE", FlxG.width, true, 43);
moreWays2.funnyColor = 0xFFfff383;
moreWays2.speed = 4.4;
moreWays2.speed = 6.8;
grpTxtScrolls.add(moreWays2);
exitMovers.set([moreWays2],
@ -245,9 +243,9 @@ class FreeplayState extends MusicBeatSubState
speed: 0.4
});
var funnyScroll3:BGScrollingText = new BGScrollingText(0, orangeBackShit.y, "BOYFRIEND", FlxG.width / 2);
funnyScroll3.funnyColor = 0xFFff9963;
funnyScroll3.speed = -0.8;
var funnyScroll3:BGScrollingText = new BGScrollingText(0, orangeBackShit.y + 10, "BOYFRIEND", FlxG.width / 2, 60);
funnyScroll3.funnyColor = 0xFFfea400;
funnyScroll3.speed = -3.8;
grpTxtScrolls.add(funnyScroll3);
exitMovers.set([funnyScroll3],
@ -256,7 +254,8 @@ class FreeplayState extends MusicBeatSubState
speed: 0.3
});
dj = new DJBoyfriend(0, -100);
// dj = new DJBoyfriend(0, -100);
dj = new DJBoyfriend(640, 366);
exitMovers.set([dj],
{
x: -dj.width * 1.6,
@ -312,6 +311,49 @@ class FreeplayState extends MusicBeatSubState
grpDifficulties.group.members[curDifficulty].visible = true;
var albumArt:FlxAtlasSprite = new FlxAtlasSprite(640, 360, Paths.animateAtlas("freeplay/albumRoll"));
albumArt.visible = false;
add(albumArt);
exitMovers.set([albumArt],
{
x: FlxG.width,
speed: 0.4,
wait: 0
});
var albumTitle:FlxSprite = new FlxSprite(947, 491).loadGraphic(Paths.image('freeplay/albumTitle-fnfvol1'));
var albumArtist:FlxSprite = new FlxSprite(1010, 607).loadGraphic(Paths.image('freeplay/albumArtist-kawaisprite'));
var difficultyStars:DifficultyStars = new DifficultyStars(140, 39);
difficultyStars.stars.visible = false;
albumTitle.visible = false;
albumArtist.visible = false;
exitMovers.set([albumTitle],
{
x: FlxG.width,
speed: 0.2,
wait: 0.1
});
exitMovers.set([albumArtist],
{
x: FlxG.width * 1.1,
speed: 0.2,
wait: 0.2
});
exitMovers.set([difficultyStars],
{
x: FlxG.width * 1.2,
speed: 0.2,
wait: 0.3
});
add(albumTitle);
add(albumArtist);
add(difficultyStars);
var overhangStuff:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, 64, FlxColor.BLACK);
overhangStuff.y -= overhangStuff.height;
add(overhangStuff);
@ -355,6 +397,28 @@ class FreeplayState extends MusicBeatSubState
txtCompletion.visible = false;
add(txtCompletion);
var letterSort:LetterSort = new LetterSort(400, 75);
add(letterSort);
letterSort.visible = false;
exitMovers.set([letterSort],
{
y: -100,
speed: 0.3
});
letterSort.changeSelectionCallback = (str) -> {
switch (str)
{
case "fav":
generateSongList({filterType: FAVORITE}, true);
case "ALL":
generateSongList(null, true);
default:
generateSongList({filterType: REGEXP, filterData: str}, true);
}
};
exitMovers.set([fp, txtCompletion, fnfHighscoreSpr],
{
x: FlxG.width,
@ -362,6 +426,24 @@ class FreeplayState extends MusicBeatSubState
});
dj.onIntroDone.add(function() {
// when boyfriend hits dat shiii
//
albumArt.visible = true;
albumArt.anim.play("");
albumArt.anim.onComplete = function() {
albumArt.anim.pause();
};
new FlxTimer().start(1, function(_) {
albumTitle.visible = true;
});
new FlxTimer().start(35 / 24, function(_) {
albumArtist.visible = true;
difficultyStars.stars.visible = true;
});
FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut});
var diffSelLeft = new DifficultySelector(20, grpDifficulties.y - 10, false, controls);
@ -370,33 +452,14 @@ class FreeplayState extends MusicBeatSubState
add(diffSelLeft);
add(diffSelRight);
letterSort.visible = true;
exitMovers.set([diffSelLeft, diffSelRight],
{
x: -diffSelLeft.width * 2,
speed: 0.26
});
var letterSort:LetterSort = new LetterSort(300, 100);
add(letterSort);
exitMovers.set([letterSort],
{
y: -100,
speed: 0.3
});
letterSort.changeSelectionCallback = (str) -> {
switch (str)
{
case "fav":
generateSongList({filterType: FAVORITE}, true);
case "ALL":
generateSongList(null, true);
default:
generateSongList({filterType: STARTSWITH, filterData: str}, true);
}
};
new FlxTimer().start(1 / 24, function(handShit) {
fnfHighscoreSpr.visible = true;
fnfFreeplay.visible = true;
@ -409,18 +472,18 @@ class FreeplayState extends MusicBeatSubState
new FlxTimer().start(1.5 / 24, function(bold) {
sillyStroke.width = 0;
sillyStroke.height = 0;
changeSelection();
});
});
pinkBack.color = 0xFFffd863;
// fnfFreeplay.visible = true;
bgDad.visible = true;
orangeBackShit.visible = true;
alsoOrangeLOL.visible = true;
grpTxtScrolls.visible = true;
});
generateSongList();
generateSongList(null, false);
// FlxG.sound.playMusic(Paths.music('title'), 0);
// FlxG.sound.music.fadeIn(2, 0, 0.8);
@ -466,9 +529,12 @@ class FreeplayState extends MusicBeatSubState
public function generateSongList(?filterStuff:SongFilter, force:Bool = false)
{
curSelected = 0;
curSelected = 1;
grpCapsules.clear();
for (cap in grpCapsules.members)
cap.kill();
// grpCapsules.clear();
// var regexp:EReg = regexp;
var tempSongs:Array<FreeplaySongData> = songs;
@ -477,6 +543,13 @@ class FreeplayState extends MusicBeatSubState
{
switch (filterStuff.filterType)
{
case REGEXP:
// filterStuff.filterData has a string with the first letter of the sorting range, and the second one
// this creates a filter to return all the songs that start with a letter between those two
var filterRegexp = new EReg("^[" + filterStuff.filterData + "].*", "i");
tempSongs = tempSongs.filter(str -> {
return filterRegexp.match(str.songName);
});
case STARTSWITH:
tempSongs = tempSongs.filter(str -> {
return str.songName.toLowerCase().startsWith(filterStuff.filterData);
@ -492,54 +565,48 @@ class FreeplayState extends MusicBeatSubState
}
}
var hsvShader:HSVShader = new HSVShader();
var randomCapsule:SongMenuItem = grpCapsules.recycle(SongMenuItem);
randomCapsule.init(FlxG.width, 0, "Random");
randomCapsule.onConfirm = function() {
trace("RANDOM SELECTED");
};
randomCapsule.y = randomCapsule.intendedY(0) + 10;
randomCapsule.targetPos.x = randomCapsule.x;
randomCapsule.alpha = 0.5;
randomCapsule.songText.visible = false;
randomCapsule.favIcon.visible = false;
randomCapsule.initJumpIn(0, force);
randomCapsule.hsvShader = hsvShader;
grpCapsules.add(randomCapsule);
for (i in 0...tempSongs.length)
{
var funnyMenu:SongMenuItem = new SongMenuItem(FlxG.width, (i * 150) + 160, tempSongs[i].songName);
var funnyMenu:SongMenuItem = grpCapsules.recycle(SongMenuItem);
funnyMenu.init(FlxG.width, 0, tempSongs[i].songName);
if (tempSongs[i].songCharacter != null) funnyMenu.setCharacter(tempSongs[i].songCharacter);
funnyMenu.onConfirm = function() {
capsuleOnConfirmDefault(funnyMenu);
};
funnyMenu.y = funnyMenu.intendedY(i + 1) + 10;
funnyMenu.targetPos.x = funnyMenu.x;
funnyMenu.ID = i;
funnyMenu.alpha = 0.5;
funnyMenu.capsule.alpha = 0.5;
funnyMenu.songText.visible = false;
funnyMenu.favIcon.visible = tempSongs[i].isFav;
funnyMenu.hsvShader = hsvShader;
// fp.updateScore(0);
var maxTimer:Float = Math.min(i, 4);
new FlxTimer().start((1 / 24) * maxTimer, function(doShit) {
funnyMenu.doJumpIn = true;
});
new FlxTimer().start((0.09 * maxTimer) + 0.85, function(lerpTmr) {
funnyMenu.doLerp = true;
});
if (!force)
{
new FlxTimer().start(((0.20 * maxTimer) / (1 + maxTimer)) + 0.75, function(swagShi) {
funnyMenu.songText.visible = true;
funnyMenu.alpha = 1;
});
}
if (i < 8) funnyMenu.initJumpIn(Math.min(i, 4), force);
else
{
funnyMenu.songText.visible = true;
funnyMenu.alpha = 1;
}
funnyMenu.forcePosition();
grpCapsules.add(funnyMenu);
var songText:Alphabet = new Alphabet(0, (70 * i) + 30, tempSongs[i].songName, true, false);
songText.x += 100;
songText.isMenuItem = true;
songText.targetY = i;
// grpSongs.add(songText);
// songText.x += 40;
// DONT PUT X IN THE FIRST PARAMETER OF new ALPHABET() !!
// songText.screenCenter(X);
}
FlxG.console.registerFunction("changeSelection", changeSelection);
changeSelection();
changeDiff();
}
@ -830,66 +897,7 @@ class FreeplayState extends MusicBeatSubState
{
// if (Assets.exists())
var poop:String = songs[curSelected].songName.toLowerCase();
// does not work properly, always just accidentally sets it to normal anyways!
/* if (!Assets.exists(Paths.json(songs[curSelected].songName + '/' + poop)))
{
// defaults to normal if HARD / EASY doesn't exist
// does not account if NORMAL doesn't exist!
FlxG.log.warn("CURRENT DIFFICULTY IS NOT CHARTED, DEFAULTING TO NORMAL!");
poop = Highscore.formatSong(songs[curSelected].songName.toLowerCase(), 1);
curDifficulty = 1;
}*/
PlayStatePlaylist.isStoryMode = false;
var songId:String = songs[curSelected].songName.toLowerCase();
var targetSong:Song = SongRegistry.instance.fetchEntry(songId);
var targetDifficulty:String = switch (curDifficulty)
{
case 0:
'easy';
case 1:
'normal';
case 2:
'hard';
default: 'normal';
};
// TODO: Implement additional difficulties into the interface properly.
if (FlxG.keys.pressed.E)
{
targetDifficulty = 'erect';
}
// TODO: Implement Pico into the interface properly.
var targetCharacter:String = 'bf';
if (FlxG.keys.pressed.P)
{
targetCharacter = 'pico';
}
PlayStatePlaylist.campaignId = songs[curSelected].levelId;
// Visual and audio effects.
FlxG.sound.play(Paths.sound('confirmMenu'));
dj.confirm();
if (targetSong != null)
{
// Load and cache the song's charts.
// TODO: Do this in the loading state.
targetSong.cacheCharts(true);
}
new FlxTimer().start(1, function(tmr:FlxTimer) {
LoadingState.loadAndSwitchState(new PlayState(
{
targetSong: targetSong,
targetDifficulty: targetDifficulty,
targetCharacter: targetCharacter,
}), true);
});
grpCapsules.members[curSelected].onConfirm();
}
}
@ -941,45 +949,124 @@ class FreeplayState extends MusicBeatSubState
}
}
function capsuleOnConfirmDefault(cap:SongMenuItem):Void
{
// var poop:String = songs[curSelected].songName.toLowerCase();
// does not work properly, always just accidentally sets it to normal anyways!
/* if (!Assets.exists(Paths.json(songs[curSelected].songName + '/' + poop)))
{
// defaults to normal if HARD / EASY doesn't exist
// does not account if NORMAL doesn't exist!
FlxG.log.warn("CURRENT DIFFICULTY IS NOT CHARTED, DEFAULTING TO NORMAL!");
poop = Highscore.formatSong(songs[curSelected].songName.toLowerCase(), 1);
curDifficulty = 1;
}*/
PlayStatePlaylist.isStoryMode = false;
var songId:String = cap.songTitle.toLowerCase();
var targetSong:Song = SongRegistry.instance.fetchEntry(songId);
var targetDifficulty:String = switch (curDifficulty)
{
case 0:
'easy';
case 1:
'normal';
case 2:
'hard';
default: 'normal';
};
// TODO: Implement additional difficulties into the interface properly.
if (FlxG.keys.pressed.E)
{
targetDifficulty = 'erect';
}
// TODO: Implement Pico into the interface properly.
var targetCharacter:String = 'bf';
if (FlxG.keys.pressed.P)
{
targetCharacter = 'pico';
}
PlayStatePlaylist.campaignId = songs[curSelected].levelId;
// Visual and audio effects.
FlxG.sound.play(Paths.sound('confirmMenu'));
dj.confirm();
// Load and cache the song's charts.
// TODO: Do this in the loading state.
targetSong.cacheCharts(true);
new FlxTimer().start(1, function(tmr:FlxTimer) {
LoadingState.loadAndSwitchState(new PlayState(
{
targetSong: targetSong,
targetDifficulty: targetDifficulty,
targetCharacter: targetCharacter,
}), true);
});
}
function changeSelection(change:Int = 0)
{
// fp.updateScore(12345);
NGio.logEvent('Fresh');
// NGio.logEvent('Fresh');
FlxG.sound.play(Paths.sound('scrollMenu'), 0.4);
// FlxG.sound.playMusic(Paths.inst(songs[curSelected].songName));
curSelected += change;
if (curSelected < 0) curSelected = grpCapsules.members.length - 1;
if (curSelected >= grpCapsules.members.length) curSelected = 0;
if (curSelected < 0) curSelected = grpCapsules.countLiving() - 1;
if (curSelected >= grpCapsules.countLiving()) curSelected = 0;
// selector.y = (70 * curSelected) + 30;
// intendedScore = Highscore.getScore(songs[curSelected].songName, curDifficulty);
intendedScore = Highscore.getScore(songs[curSelected].songName, curDifficulty);
intendedCompletion = Highscore.getCompletion(songs[curSelected].songName, curDifficulty);
if (songs[curSelected] != null)
{
intendedScore = Highscore.getScore(songs[curSelected].songName, curDifficulty);
intendedCompletion = Highscore.getCompletion(songs[curSelected].songName, curDifficulty);
}
else
{
intendedScore = 0;
intendedCompletion = 0;
}
// lerpScore = 0;
#if PRELOAD_ALL
// FlxG.sound.playMusic(Paths.inst(songs[curSelected].songName), 0);
#end
var bullShit:Int = 0;
for (index => capsule in grpCapsules.members)
{
capsule.selected = false;
index += 1;
capsule.targetPos.y = ((index - curSelected) * 150) + 160;
capsule.selected = index == curSelected + 1;
capsule.targetPos.y = capsule.intendedY(index - curSelected);
capsule.targetPos.x = 270 + (60 * (Math.sin(index - curSelected)));
// capsule.targetPos.x = 320 + (40 * (index - curSelected));
if (index < curSelected) capsule.targetPos.y -= 100; // another 100 for good measure
}
if (grpCapsules.members.length > 0) grpCapsules.members[curSelected].selected = true;
if (grpCapsules.countLiving() > 0)
{
if (curSelected == 0)
{
FlxG.sound.playMusic(Paths.music('freeplay/freeplayRandom'), 0);
FlxG.sound.music.fadeIn(2, 0, 0.8);
}
grpCapsules.members[curSelected].selected = true;
}
}
}
@ -1019,7 +1106,10 @@ class DifficultySelector extends FlxSprite
whiteShader.colorSet = true;
scale.x = scale.y = 0.5;
new FlxTimer().start(2 / 24, function(tmr) {
scale.x = scale.y = 1;
whiteShader.colorSet = false;
updateHitbox();
});
@ -1035,6 +1125,7 @@ typedef SongFilter =
enum abstract FilterType(String)
{
var STARTSWITH;
var REGEXP;
var FAVORITE;
var ALL;
}

View file

@ -49,9 +49,9 @@ class Paths
return getPath(file, type, library);
}
public static inline function animateAtlas(path:String, library:String)
public static inline function animateAtlas(path:String, ?library:String)
{
return getLibraryPathForce('images/$path', library);
return getLibraryPath('images/$path', library);
}
inline static public function txt(key:String, ?library:String)

View file

@ -0,0 +1,49 @@
package funkin.audio;
import flash.media.Sound;
#if flash11
import flash.utils.ByteArray;
#end
import flixel.sound.FlxSound;
import flixel.system.FlxAssets.FlxSoundAsset;
import openfl.Assets;
#if (openfl >= "8.0.0")
import openfl.utils.AssetType;
#end
/**
* a FlxSound that just overrides loadEmbedded to allow for "streamed" sounds to load with better performance!
*/
class FlxStreamSound extends FlxSound
{
public function new()
{
super();
}
override public function loadEmbedded(EmbeddedSound:FlxSoundAsset, Looped:Bool = false, AutoDestroy:Bool = false, ?OnComplete:Void->Void):FlxSound
{
if (EmbeddedSound == null) return this;
cleanup(true);
if ((EmbeddedSound is Sound))
{
_sound = EmbeddedSound;
}
else if ((EmbeddedSound is Class))
{
_sound = Type.createInstance(EmbeddedSound, []);
}
else if ((EmbeddedSound is String))
{
if (Assets.exists(EmbeddedSound, AssetType.SOUND)
|| Assets.exists(EmbeddedSound, AssetType.MUSIC)) _sound = Assets.getMusic(EmbeddedSound);
else
FlxG.log.error('Could not find a Sound asset with an ID of \'$EmbeddedSound\'.');
}
// NOTE: can't pull ID3 info from embedded sound currently
return init(Looped, AutoDestroy, OnComplete);
}
}

View file

@ -7,6 +7,7 @@ import flixel.math.FlxMath;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import flixel.util.FlxSort;
import flixel.util.FlxTimer;
// its kinda like marqeee html lol!
class BGScrollingText extends FlxSpriteGroup
@ -16,36 +17,53 @@ class BGScrollingText extends FlxSpriteGroup
public var widthShit:Float = FlxG.width;
public var placementOffset:Float = 20;
public var speed:Float = 1;
public var size(default, set):Int = 48;
public var funnyColor(default, set):Int = 0xFFFFFFFF;
public function new(x:Float, y:Float, text:String, widthShit:Float = 100)
public function new(x:Float, y:Float, text:String, widthShit:Float = 100, ?bold:Bool = false, ?size:Int = 48)
{
super(x, y);
this.widthShit = widthShit;
if (size != null) this.size = size;
grpTexts = new FlxTypedSpriteGroup<FlxText>();
add(grpTexts);
var testText:FlxText = new FlxText(0, 0, 0, text, 48);
var testText:FlxText = new FlxText(0, 0, 0, text, this.size);
testText.font = "5by7";
testText.bold = bold;
testText.updateHitbox();
grpTexts.add(testText);
var needed:Int = Math.ceil(widthShit / testText.frameWidth);
var needed:Int = Math.ceil(widthShit / testText.frameWidth) + 1;
for (i in 0...needed)
{
var lmfao:Int = i + 1;
var coolText:FlxText = new FlxText((lmfao * testText.frameWidth) + (lmfao * 20), 0, 0, text, 48);
var coolText:FlxText = new FlxText((lmfao * testText.frameWidth) + (lmfao * 20), 0, 0, text, this.size);
coolText.font = "5by7";
coolText.bold = bold;
coolText.updateHitbox();
grpTexts.add(coolText);
}
}
function set_size(value:Int):Int
{
if (grpTexts != null)
{
grpTexts.forEach(function(txt:FlxText) {
txt.size = value;
});
}
this.size = value;
return value;
}
function set_funnyColor(col:Int):Int
{
grpTexts.forEach(function(txt) {
@ -55,7 +73,7 @@ class BGScrollingText extends FlxSpriteGroup
return col;
}
override function update(elapsed:Float)
override public function update(elapsed:Float)
{
for (txt in grpTexts.group)
{
@ -66,14 +84,16 @@ class BGScrollingText extends FlxSpriteGroup
if (txt.x < -txt.frameWidth)
{
txt.x = grpTexts.group.members[grpTexts.length - 1].x + grpTexts.group.members[grpTexts.length - 1].frameWidth + placementOffset;
sortTextShit();
}
}
else
{
if (txt.x > widthShit)
if (txt.x > txt.frameWidth * 2)
{
txt.x = grpTexts.group.members[0].x - grpTexts.group.members[0].frameWidth - placementOffset;
sortTextShit();
}
}

View file

@ -0,0 +1,49 @@
package funkin.freeplayStuff;
import openfl.filters.BitmapFilterQuality;
import flixel.text.FlxText;
import flixel.group.FlxSpriteGroup;
import funkin.shaderslmfao.GaussianBlurShader;
class CapsuleText extends FlxSpriteGroup
{
public var blurredText:FlxText;
var whiteText:FlxText;
public var text(default, set):String;
public function new(x:Float, y:Float, songTitle:String, size:Float)
{
super(x, y);
blurredText = initText(songTitle, size);
blurredText.shader = new GaussianBlurShader(1);
whiteText = initText(songTitle, size);
// whiteText.shader = new GaussianBlurShader(0.3);
text = songTitle;
blurredText.color = 0xFF00ccff;
whiteText.color = 0xFFFFFFFF;
add(blurredText);
add(whiteText);
}
function initText(songTitle, size:Float):FlxText
{
var text:FlxText = new FlxText(0, 0, 0, songTitle, Std.int(size));
text.font = "5by7";
return text;
}
function set_text(value:String):String
{
blurredText.text = value;
whiteText.text = value;
whiteText.textField.filters = [
new openfl.filters.GlowFilter(0x00ccff, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM),
// new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW)
];
return value;
}
}

View file

@ -3,8 +3,12 @@ package funkin.freeplayStuff;
import flixel.FlxSprite;
import flixel.util.FlxSignal;
import funkin.util.assets.FlxAnimationUtil;
import funkin.graphics.adobeanimate.FlxAtlasSprite;
import flixel.system.FlxSound;
import flixel.util.FlxTimer;
import funkin.audio.FlxStreamSound;
class DJBoyfriend extends FlxSprite
class DJBoyfriend extends FlxAtlasSprite
{
// Represents the sprite's current status.
// Without state machines I would have driven myself crazy years ago.
@ -20,20 +24,55 @@ class DJBoyfriend extends FlxSprite
// TODO: Switch this class to use SwagSprite instead.
public var animOffsets:Map<String, Array<Dynamic>>;
static final SPOOK_PERIOD:Float = 180.0;
var gotSpooked:Bool = false;
static final SPOOK_PERIOD:Float = 120.0;
static final TV_PERIOD:Float = 180.0;
// Time since dad last SPOOKED you.
var timeSinceSpook:Float = 0;
public function new(x:Float, y:Float)
{
super(x, y);
super(x, y, Paths.animateAtlas("freeplay/freeplay-boyfriend", "preload"));
animOffsets = new Map<String, Array<Dynamic>>();
setupAnimations();
anim.callback = function(name, number) {
switch (name)
{
case "Boyfriend DJ watchin tv OG":
if (number == 85) runTvLogic();
default:
}
};
animation.finishCallback = onFinishAnim;
setupAnimations();
trace(listAnimations());
FlxG.debugger.track(this);
FlxG.console.registerObject("dj", this);
anim.onComplete = onFinishAnim;
FlxG.console.registerFunction("tv", function() {
currentState = TV;
});
}
/*
[remote hand under,boyfriend top head,brim piece,arm cringe l,red lazer,dj arm in,bf fist pump arm,hand raised right,forearm left,fist shaking,bf smile eyes closed face,arm cringe r,bf clenched face,face shrug,boyfriend falling,blue tint 1,shirt sleeve,bf clenched fist,head BF relaxed,blue tint 2,hand down left,blue tint 3,blue tint 4,head less smooshed,blue tint 5,boyfriend freeplay,BF head slight turn,blue tint 6,arm shrug l,blue tint 7,shoulder raised w sleeve,blue tint 8,fist pump face,blue tint 9,foot rested light,hand turnaround,arm chill right,Boyfriend DJ,arm shrug r,head back bf,hat top piece,dad bod,face surprise snap,Boyfriend DJ fist pump,office chair,foot rested right,chest down,office chair upright,body chill,bf dj afk,head mouth open dad,BF Head defalt HAIR BLOWING,hand shrug l,face piece,foot wag,turn table,shoulder up left,turntable lights,boyfriend dj body shirt blowing,body chunk turned,hand down right,dj arm out,hand shrug r,body chest out,rave hand,palm,chill face default,head back semi bf,boyfriend bottom head,DJ arm,shoulder right dad,bf surprise,boyfriend dj body,hs1,Boyfriend DJ watchin tv OG,spinning disk,hs2,arm chill left,boyfriend dj intro,hs3,hs4,chill face extra,hs5,remote hand upright,hs6,pant over table,face surprise,bf arm peace,arm turnaround,bf eyes 1,arm slammed table,eye squit,leg BF,head mid piece,arm backing,arm swoopin in,shoe right lowering,forearm right,hand out,blue tint 10,body falling back,remote thumb press,shoulder,hair spike single,bf bent
arm,crt,foot raised right,dad hand,chill face 1,chill face 2,clenched fist,head SMOOSHED,shoulder left dad,df1,body chunk upright,df2,df3,df4,hat front piece,df5,foot rested right 2,hand in,arm spun,shoe raised left,bf 1 finger hand,bf mouth 1,Boyfriend DJ confirm,forearm down ,hand raised left,remote thumb up]
*/
override public function listAnimations():Array<String>
{
var anims:Array<String> = [];
@:privateAccess
for (animKey in anim.symbolDictionary)
{
anims.push(animKey.name);
}
return anims;
}
public override function update(elapsed:Float):Void
@ -44,51 +83,68 @@ class DJBoyfriend extends FlxSprite
{
case Intro:
// Play the intro animation then leave this state immediately.
if (getCurrentAnimation() != 'intro') playAnimation('intro', true);
if (getCurrentAnimation() != 'boyfriend dj intro') playFlashAnimation('boyfriend dj intro', true);
timeSinceSpook = 0;
case Idle:
// We are in this state the majority of the time.
if (getCurrentAnimation() != 'idle' || animation.finished)
if (getCurrentAnimation() != 'Boyfriend DJ' || anim.finished)
{
if (timeSinceSpook > SPOOK_PERIOD)
if (timeSinceSpook > SPOOK_PERIOD && !gotSpooked)
{
currentState = Spook;
}
else if (timeSinceSpook > TV_PERIOD)
{
currentState = TV;
}
else
{
playAnimation('idle', false);
playFlashAnimation('Boyfriend DJ', false);
}
}
timeSinceSpook += elapsed;
case Confirm:
if (getCurrentAnimation() != 'confirm') playAnimation('confirm', false);
if (getCurrentAnimation() != 'Boyfriend DJ confirm') playFlashAnimation('Boyfriend DJ confirm', false);
timeSinceSpook = 0;
case Spook:
if (getCurrentAnimation() != 'spook')
if (getCurrentAnimation() != 'bf dj afk')
{
onSpook.dispatch();
playAnimation('spook', false);
playFlashAnimation('bf dj afk', false);
}
timeSinceSpook = 0;
case TV:
if (getCurrentAnimation() != 'Boyfriend DJ watchin tv OG') playFlashAnimation('Boyfriend DJ watchin tv OG', true);
timeSinceSpook = 0;
default:
// I shit myself.
}
}
function onFinishAnim(name:String):Void
function onFinishAnim():Void
{
var name = anim.curSymbol.name;
switch (name)
{
case "intro":
case "boyfriend dj intro":
// trace('Finished intro');
currentState = Idle;
onIntroDone.dispatch();
case "idle":
case "Boyfriend DJ":
// trace('Finished idle');
case "spook":
case "bf dj afk":
// trace('Finished spook');
currentState = Idle;
case "confirm":
case "Boyfriend DJ confirm":
case "Boyfriend DJ watchin tv OG":
var frame:Int = FlxG.random.bool(33) ? 112 : 166;
if (FlxG.random.bool(10))
{
frame = 60;
// boyfriend switches channel code?
}
anim.play("Boyfriend DJ watchin tv OG", true, false, frame);
// trace('Finished confirm');
}
}
@ -100,19 +156,66 @@ class DJBoyfriend extends FlxSprite
function setupAnimations():Void
{
frames = FlxAnimationUtil.combineFramesCollections(Paths.getSparrowAtlas('freeplay/bfFreeplay'), Paths.getSparrowAtlas('freeplay/bf-freeplay-afk'));
// frames = FlxAnimationUtil.combineFramesCollections(Paths.getSparrowAtlas('freeplay/bfFreeplay'), Paths.getSparrowAtlas('freeplay/bf-freeplay-afk'));
animation.addByPrefix('intro', "boyfriend dj intro", 24, false);
addOffset('intro', 0, 0);
// animation.addByPrefix('intro', "boyfriend dj intro", 24, false);
addOffset('boyfriend dj intro', 8, 3);
animation.addByPrefix('idle', "Boyfriend DJ0", 24, false);
addOffset('idle', -4, -426);
// animation.addByPrefix('idle', "Boyfriend DJ0", 24, false);
addOffset('Boyfriend DJ', 0, 0);
animation.addByPrefix('confirm', "Boyfriend DJ confirm", 24, false);
addOffset('confirm', 40, -451);
// animation.addByPrefix('confirm', "Boyfriend DJ confirm", 24, false);
addOffset('Boyfriend DJ confirm', 0, 0);
animation.addByPrefix('spook', "bf dj afk0", 24, false);
addOffset('spook', -3, -272);
// animation.addByPrefix('spook', "bf dj afk0", 24, false);
addOffset('bf dj afk', 0, 0);
}
var cartoonSnd:FlxStreamSound;
public var playingCartoon:Bool = false;
public function runTvLogic()
{
if (cartoonSnd == null)
{
// tv is OFF, but getting turned on
FlxG.sound.play(Paths.sound('tv_on'));
cartoonSnd = new FlxStreamSound();
FlxG.sound.defaultSoundGroup.add(cartoonSnd);
}
else
{
// plays it smidge after the click
new FlxTimer().start(0.1, function(_) {
FlxG.sound.play(Paths.sound('channel_switch'));
});
}
// cartoonSnd.loadEmbedded(Paths.sound("cartoons/peck"));
// cartoonSnd.play();
loadCartoon();
}
function loadCartoon()
{
cartoonSnd.loadEmbedded(Paths.sound(getRandomFlashToon()), false, false, function() {
anim.play("Boyfriend DJ watchin tv OG", true, false, 60);
});
cartoonSnd.play(true, FlxG.random.float(0, cartoonSnd.length));
}
var cartoonList:Array<String> = openfl.utils.Assets.list().filter(function(path) return path.startsWith("assets/sounds/cartoons/"));
function getRandomFlashToon():String
{
var randomFile = FlxG.random.getObject(cartoonList);
randomFile = randomFile.replace("assets/sounds/", "");
randomFile = randomFile.substring(0, randomFile.length - 4);
return randomFile;
}
public function confirm():Void
@ -125,15 +228,15 @@ class DJBoyfriend extends FlxSprite
animOffsets[name] = [x, y];
}
public function getCurrentAnimation():String
override public function getCurrentAnimation():String
{
if (this.animation == null || this.animation.curAnim == null) return "";
return this.animation.curAnim.name;
if (this.anim == null || this.anim.curSymbol == null) return "";
return this.anim.curSymbol.name;
}
public function playAnimation(AnimName:String, Force:Bool = false, Reversed:Bool = false, Frame:Int = 0):Void
public function playFlashAnimation(id:String, ?Force:Bool = false, ?Reverse:Bool = false, ?Frame:Int = 0):Void
{
animation.play(AnimName, Force, Reversed, Frame);
anim.play(id, Force, Reverse, Frame);
applyAnimOffset();
}
@ -156,4 +259,5 @@ enum DJBoyfriendState
Idle;
Confirm;
Spook;
TV;
}

View file

@ -0,0 +1,106 @@
package funkin.freeplayStuff;
import flixel.group.FlxSpriteGroup;
import funkin.graphics.adobeanimate.FlxAtlasSprite;
import funkin.shaderslmfao.HSVShader;
class DifficultyStars extends FlxSpriteGroup
{
/**
* Internal handler var for difficulty... ranges from 0... to 15
* 0 is 1 star... 15 is 0 stars!
*/
var curDifficulty(default, set):Int = 0;
/**
* Range between 0 and 15
*/
public var difficulty(default, set):Int = 1;
public var stars:FlxAtlasSprite;
var flames:FreeplayFlames;
var hsvShader:HSVShader;
public function new(x:Float, y:Float)
{
super(x, y);
hsvShader = new HSVShader();
flames = new FreeplayFlames(0, 0);
add(flames);
stars = new FlxAtlasSprite(0, 0, Paths.animateAtlas("freeplay/freeplayStars"));
stars.anim.play("diff stars");
add(stars);
stars.shader = hsvShader;
for (memb in flames.members)
memb.shader = hsvShader;
}
override function update(elapsed:Float):Void
{
super.update(elapsed);
// "loops" the current animation
// for clarity, the animation file looks like
// frame : stars
// 0-99: 1 star
// 100-199: 2 stars
// ......
// 1300-1499: 15 stars
// 1500 : 0 stars
if (curDifficulty < 15 && stars.anim.curFrame >= (curDifficulty + 1) * 100)
{
stars.anim.play("diff stars", true, false, curDifficulty * 100);
}
}
function set_difficulty(value:Int):Int
{
difficulty = value;
if (difficulty <= 0)
{
difficulty = 0;
curDifficulty = 15;
}
else if (difficulty <= 15)
{
difficulty = value;
curDifficulty = difficulty - 1;
}
else
{
difficulty = 15;
curDifficulty = difficulty - 1;
}
if (difficulty > 10) flames.flameCount = difficulty - 10;
else
flames.flameCount = 0;
return difficulty;
}
function set_curDifficulty(value:Int):Int
{
curDifficulty = value;
if (curDifficulty == 15)
{
stars.anim.play("diff stars", true, false, 1500);
stars.anim.pause();
}
else
{
stars.anim.curFrame = Std.int(curDifficulty * 100);
stars.anim.play("diff stars", true, false, curDifficulty * 100);
}
return curDifficulty;
}
}

View file

@ -0,0 +1,117 @@
package funkin.freeplayStuff;
import flixel.group.FlxSpriteGroup;
import flixel.FlxSprite;
import flixel.util.FlxTimer;
class FreeplayFlames extends FlxSpriteGroup
{
var flameX(default, set):Float = 917;
var flameY(default, set):Float = 103;
var flameSpreadX(default, set):Float = 29;
var flameSpreadY(default, set):Float = 6;
public var flameCount(default, set):Int = 0;
var flameTimer:Float = 0.25;
public function new(x:Float, y:Float)
{
super(x, y);
for (i in 0...5)
{
var flame:FlxSprite = new FlxSprite(flameX + (flameSpreadX * i), flameY + (flameSpreadY * i));
flame.frames = Paths.getSparrowAtlas("freeplay/freeplayFlame");
flame.animation.addByPrefix("flame", "fire loop", FlxG.random.int(23, 25), false);
flame.animation.play("flame");
flame.visible = false;
flameCount = 0;
// sets the loop... maybe better way to do this lol!
flame.animation.finishCallback = function(_) {
flame.animation.play("flame", true, false, 2);
};
add(flame);
}
}
var properPositions:Bool = false;
override public function update(elapsed:Float):Void
{
super.update(elapsed);
// doesn't work in create()/new() for some reason
// so putting it here bwah!
if (!properPositions)
{
setFlamePositions();
properPositions = true;
}
}
function set_flameCount(value:Int):Int
{
this.flameCount = value;
var visibleCount:Int = 0;
for (i in 0...5)
{
if (members[i] == null) continue;
var flame:FlxSprite = members[i];
if (i < flameCount)
{
if (!flame.visible)
{
new FlxTimer().start(flameTimer * visibleCount, function(_) {
flame.animation.play("flame", true);
flame.visible = true;
});
visibleCount++;
}
}
else
{
flame.visible = false;
}
}
return this.flameCount;
}
function setFlamePositions()
{
for (i in 0...5)
{
var flame:FlxSprite = members[i];
flame.x = flameX + (flameSpreadX * i);
flame.y = flameY + (flameSpreadY * i);
}
}
function set_flameX(value:Float):Float
{
this.flameX = value;
setFlamePositions();
return this.flameX;
}
function set_flameY(value:Float):Float
{
this.flameY = value;
setFlamePositions();
return this.flameY;
}
function set_flameSpreadX(value:Float):Float
{
this.flameSpreadX = value;
setFlamePositions();
return this.flameSpreadX;
}
function set_flameSpreadY(value:Float):Float
{
this.flameSpreadY = value;
setFlamePositions();
return this.flameSpreadY;
}
}

View file

@ -4,38 +4,68 @@ import flixel.FlxSprite;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.group.FlxGroup;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
import flixel.tweens.FlxTween;
import flixel.tweens.FlxEase;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import funkin.graphics.adobeanimate.FlxAtlasSprite;
class LetterSort extends FlxTypedSpriteGroup<FreeplayLetter>
class LetterSort extends FlxTypedSpriteGroup<FlxSprite>
{
public var letters:Array<FreeplayLetter> = [];
var curSelection:Int = 0;
// starts at 2, cuz that's the middle letter on start (accounting for fav and #, it should begin at ALL filter)
var curSelection:Int = 2;
public var changeSelectionCallback:String->Void;
var leftArrow:FlxSprite;
var rightArrow:FlxSprite;
var grpSeperators:Array<FlxSprite> = [];
public function new(x, y)
{
super(x, y);
var leftArrow:FreeplayLetter = new FreeplayLetter(-20, 0);
leftArrow.animation.play("arrow");
leftArrow = new FlxSprite(-20, 15).loadGraphic(Paths.image("freeplay/miniArrow"));
// leftArrow.animation.play("arrow");
leftArrow.flipX = true;
add(leftArrow);
for (i in 0...6)
for (i in 0...5)
{
var letter:FreeplayLetter = new FreeplayLetter(i * 80, 0, i);
letter.x += 50;
letter.y += 50;
letter.ogY = y;
// letter.visible = false;
add(letter);
letters.push(letter);
if (i == 3) letter.alpha = 0.6;
if (i != 2) letter.scale.x = letter.scale.y = 0.8;
var sep:FreeplayLetter = new FreeplayLetter((i * 80) + 50, 0);
sep.animation.play("seperator");
var darkness:Float = Math.abs(i - 2) / 6;
letter.color = letter.color.getDarkened(darkness);
// don't put the last seperator
if (i == 4) continue;
var sep:FlxSprite = new FlxSprite((i * 80) + 55, 20).loadGraphic(Paths.image("freeplay/seperator"));
// sep.animation.play("seperator");
sep.color = letter.color.getDarkened(darkness);
add(sep);
grpSeperators.push(sep);
}
// changeSelection(-3);
rightArrow = new FlxSprite(380, 15).loadGraphic(Paths.image("freeplay/miniArrow"));
// rightArrow.animation.play("arrow");
add(rightArrow);
changeSelection(0);
}
override function update(elapsed:Float)
@ -48,53 +78,168 @@ class LetterSort extends FlxTypedSpriteGroup<FreeplayLetter>
public function changeSelection(diff:Int = 0)
{
for (letter in letters)
letter.changeLetter(diff);
var ezTimer:Int->FlxSprite->Float->Void = function(frameNum:Int, spr:FlxSprite, offsetNum:Float) {
new FlxTimer().start(frameNum / 24, function(_) {
spr.offset.x = offsetNum;
});
};
if (changeSelectionCallback != null) changeSelectionCallback(letters[3].arr[letters[3].curLetter]); // bullshit and long lol!
var positions:Array<Float> = [-10, -22, 2, 0];
if (diff < 0)
{
for (sep in grpSeperators)
{
ezTimer(0, sep, positions[0]);
ezTimer(1, sep, positions[1]);
ezTimer(2, sep, positions[2]);
ezTimer(3, sep, positions[3]);
}
for (index => letter in letters)
{
letter.offset.x = positions[0];
new FlxTimer().start(1 / 24, function(_) {
letter.offset.x = positions[1];
if (index == 0) letter.visible = false;
});
new FlxTimer().start(2 / 24, function(_) {
letter.offset.x = positions[2];
if (index == 0.) letter.visible = true;
});
if (index == 2)
{
ezTimer(3, letter, 0);
// letter.offset.x = 0;
continue;
}
ezTimer(3, letter, positions[3]);
}
leftArrow.offset.x = 3;
new FlxTimer().start(2 / 24, function(_) {
leftArrow.offset.x = 0;
});
}
else if (diff > 0)
{
for (sep in grpSeperators)
{
ezTimer(0, sep, -positions[0]);
ezTimer(1, sep, -positions[1]);
ezTimer(2, sep, -positions[2]);
ezTimer(3, sep, -positions[3]);
}
// same timing and functions and shit as the left one... except to the right!!
for (index => letter in letters)
{
letter.offset.x = -positions[0];
new FlxTimer().start(1 / 24, function(_) {
letter.offset.x = -positions[1];
if (index == 0) letter.visible = false;
});
new FlxTimer().start(2 / 24, function(_) {
letter.offset.x = -positions[2];
if (index == 0) letter.visible = true;
});
if (index == 2)
{
ezTimer(3, letter, 0);
// letter.offset.x = 0;
continue;
}
ezTimer(3, letter, -positions[3]);
}
rightArrow.offset.x = -3;
new FlxTimer().start(2 / 24, function(_) {
rightArrow.offset.x = 0;
});
}
curSelection += diff;
if (curSelection < 0) curSelection = letters[0].arr.length - 1;
if (curSelection >= letters[0].arr.length) curSelection = 0;
for (letter in letters)
letter.changeLetter(diff, curSelection);
if (changeSelectionCallback != null) changeSelectionCallback(letters[2].arr[letters[2].curLetter]); // bullshit and long lol!
}
}
class FreeplayLetter extends FlxSprite
class FreeplayLetter extends FlxAtlasSprite
{
public var arr:Array<String> = [];
public var curLetter:Int = 0;
public var ogY:Float = 0;
public function new(x:Float, y:Float, ?letterInd:Int)
{
super(x, y);
super(x, y, Paths.animateAtlas("freeplay/sortedLetters"));
// frames = Paths.getSparrowAtlas("freeplay/letterStuff");
// this.anim.play("AB");
// trace(this.anim.symbolDictionary);
frames = Paths.getSparrowAtlas("freeplay/letterStuff");
var alphabet:String = "abcdefghijklmnopqrstuvwxyz";
arr = alphabet.split("");
arr.insert(0, "#");
var alphabet:String = "AB-CD-EH-I L-MN-OR-s-t-UZ";
arr = alphabet.split("-");
arr.insert(0, "ALL");
arr.insert(0, "fav");
arr.insert(0, "#");
for (str in arr)
{
animation.addByPrefix(str, str + " "); // string followed by a space! intentional!
}
// trace(arr);
animation.addByPrefix("arrow", "mini arrow");
animation.addByPrefix("seperator", "seperator");
// for (str in arr)
// {
// animation.addByPrefix(str, str + " "); // string followed by a space! intentional!
// }
// animation.addByPrefix("arrow", "mini arrow");
// animation.addByPrefix("seperator", "seperator");
if (letterInd != null)
{
animation.play(arr[letterInd]);
this.anim.play(arr[letterInd] + " move");
this.anim.pause();
curLetter = letterInd;
}
}
public function changeLetter(diff:Int = 0)
public function changeLetter(diff:Int = 0, ?curSelection:Int)
{
curLetter += diff;
if (curLetter < 0) curLetter = arr.length - 1;
if (curLetter >= arr.length) curLetter = 0;
animation.play(arr[curLetter]);
var animName:String = arr[curLetter] + " move";
switch (arr[curLetter])
{
case "I L":
animName = "IL move";
case "s":
animName = "S move";
case "t":
animName = "T move";
}
this.anim.play(animName);
if (curSelection != curLetter)
{
this.anim.pause();
}
// updateHitbox();
}
}

View file

@ -1,5 +1,8 @@
package funkin.freeplayStuff;
import funkin.shaderslmfao.HSVShader;
import funkin.shaderslmfao.GaussianBlurShader;
import flixel.group.FlxGroup;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
@ -7,17 +10,29 @@ import flixel.group.FlxSpriteGroup;
import flixel.math.FlxMath;
import flixel.math.FlxPoint;
import flixel.text.FlxText;
import flixel.util.FlxTimer;
import funkin.shaderslmfao.Grayscale;
class SongMenuItem extends FlxSpriteGroup
{
var capsule:FlxSprite;
public var capsule:FlxSprite;
public var selected(default, set):Bool = false;
var pixelIcon:FlxSprite;
public var selected(default, set):Bool;
public var songTitle:String = "Test";
public var songText:FlxText;
public var songText:CapsuleText;
public var favIcon:FlxSprite;
public var ranking:FlxSprite;
var ranks:Array<String> = ["fail", "average", "great", "excellent", "perfect"];
// lol...
var diffRanks:Array<String> = [
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "14", "15"
];
public var targetPos:FlxPoint = new FlxPoint();
public var doLerp:Bool = false;
@ -25,7 +40,12 @@ class SongMenuItem extends FlxSpriteGroup
public var doJumpOut:Bool = false;
public function new(x:Float, y:Float, song:String)
public var onConfirm:Void->Void;
public var diffGrayscale:Grayscale;
public var hsvShader(default, set):HSVShader;
public function new(x:Float, y:Float, song:String, ?character:String)
{
super(x, y);
@ -38,19 +58,144 @@ class SongMenuItem extends FlxSpriteGroup
// capsule.animation
add(capsule);
songText = new FlxText(120, 40, 0, songTitle, 40);
songText.font = "5by7";
songText.color = 0xFF43C1EA;
add(songText);
// doesn't get added, simply is here to help with visibility of things for the pop in!
grpHide = new FlxGroup();
favIcon = new FlxSprite(440, 40);
var rank:String = FlxG.random.getObject(ranks);
ranking = new FlxSprite(capsule.width * 0.84, 30);
ranking.loadGraphic(Paths.image("freeplay/ranks/" + rank));
ranking.scale.x = ranking.scale.y = realScaled;
ranking.alpha = 0.75;
ranking.origin.set(capsule.origin.x - ranking.x, capsule.origin.y - ranking.y);
add(ranking);
grpHide.add(ranking);
diffGrayscale = new Grayscale(1);
var diffRank = new FlxSprite(145, 90).loadGraphic(Paths.image("freeplay/diffRankings/diff" + FlxG.random.getObject(diffRanks)));
diffRank.shader = diffGrayscale;
diffRank.visible = false;
add(diffRank);
diffRank.origin.set(capsule.origin.x - diffRank.x, capsule.origin.y - diffRank.y);
grpHide.add(diffRank);
switch (rank)
{
case "perfect":
ranking.x -= 10;
}
songText = new CapsuleText(capsule.width * 0.26, 45, songTitle, Std.int(40 * realScaled));
add(songText);
grpHide.add(songText);
pixelIcon = new FlxSprite(155, 15);
pixelIcon.makeGraphic(32, 32, 0x00000000);
pixelIcon.antialiasing = false;
pixelIcon.active = false;
add(pixelIcon);
grpHide.add(pixelIcon);
if (character != null) setCharacter(character);
favIcon = new FlxSprite(400, 40);
favIcon.frames = Paths.getSparrowAtlas('freeplay/favHeart');
favIcon.animation.addByPrefix('fav', "favorite heart", 24, false);
favIcon.animation.play('fav');
favIcon.setGraphicSize(60, 60);
favIcon.setGraphicSize(50, 50);
favIcon.visible = false;
add(favIcon);
// grpHide.add(favIcon);
selected = selected; // just to kickstart the set_selected
setVisibleGrp(false);
}
function set_hsvShader(value:HSVShader):HSVShader
{
this.hsvShader = value;
capsule.shader = hsvShader;
songText.shader = hsvShader;
return value;
}
function textAppear()
{
songText.scale.x = 1.7;
songText.scale.y = 0.2;
new FlxTimer().start(1 / 24, function(_) {
songText.scale.x = 0.4;
songText.scale.y = 1.4;
});
new FlxTimer().start(2 / 24, function(_) {
songText.scale.x = songText.scale.y = 1;
});
}
function setVisibleGrp(value:Bool)
{
for (spr in grpHide.members)
{
spr.visible = value;
}
if (value) textAppear();
selectedAlpha();
}
public function init(x:Float, y:Float, song:String, ?character:String)
{
this.x = x;
this.y = y;
this.songTitle = song;
songText.text = this.songTitle;
if (character != null) setCharacter(character);
selected = selected;
}
/**
* Set the character displayed next to this song in the freeplay menu.
* @param char The character ID used by this song.
* If the character has no freeplay icon, a warning will be thrown and nothing will display.
*/
public function setCharacter(char:String)
{
var charPath:String = "freeplay/icons/";
trace(char);
switch (char)
{
case "monster-christmas":
charPath += "monsterpixel";
case "mom-car":
charPath += "mommypixel";
case "dad":
charPath += "daddypixel";
case "darnell-blazin":
charPath += "darnellpixel";
case "senpai-angry":
charPath += "senpaipixel";
default:
charPath += char + "pixel";
}
if (!openfl.utils.Assets.exists(Paths.image(charPath)))
{
trace('[WARN] Character ${char} has no freeplay icon.');
return;
}
pixelIcon.loadGraphic(Paths.image(charPath));
pixelIcon.scale.x = pixelIcon.scale.y = 2;
pixelIcon.origin.x = 100;
// pixelIcon.origin.x = capsule.origin.x;
// pixelIcon.offset.x -= pixelIcon.origin.x;
}
var frameInTicker:Float = 0;
@ -63,6 +208,63 @@ class SongMenuItem extends FlxSpriteGroup
var xPosLerpLol:Array<Float> = [0.9, 0.4, 0.16, 0.16, 0.22, 0.22, 0.245]; // NUMBERS ARE JANK CUZ THE SCALING OR WHATEVER
var xPosOutLerpLol:Array<Float> = [0.245, 0.75, 0.98, 0.98, 1.2]; // NUMBERS ARE JANK CUZ THE SCALING OR WHATEVER
public var realScaled:Float = 0.8;
public function initJumpIn(maxTimer:Float, ?force:Bool):Void
{
frameInTypeBeat = 0;
new FlxTimer().start((1 / 24) * maxTimer, function(doShit) {
doJumpIn = true;
});
new FlxTimer().start((0.09 * maxTimer) + 0.85, function(lerpTmr) {
doLerp = true;
});
if (force)
{
visible = true;
capsule.alpha = 1;
setVisibleGrp(true);
}
else
{
new FlxTimer().start((xFrames.length / 24) * 2.5, function(_) {
visible = true;
capsule.alpha = 1;
setVisibleGrp(true);
});
}
}
var grpHide:FlxGroup;
public function forcePosition()
{
visible = true;
capsule.alpha = 1;
selectedAlpha();
doLerp = true;
doJumpIn = false;
doJumpOut = false;
frameInTypeBeat = xFrames.length;
frameOutTypeBeat = 0;
capsule.scale.x = xFrames[frameInTypeBeat - 1];
capsule.scale.y = 1 / xFrames[frameInTypeBeat - 1];
// x = FlxG.width * xPosLerpLol[Std.int(Math.min(frameInTypeBeat - 1, xPosLerpLol.length - 1))];
x = targetPos.x;
y = targetPos.y;
capsule.scale.x *= realScaled;
capsule.scale.y *= realScaled;
setVisibleGrp(true);
}
override function update(elapsed:Float)
{
if (doJumpIn)
@ -73,10 +275,13 @@ class SongMenuItem extends FlxSpriteGroup
{
frameInTicker = 0;
scale.x = xFrames[frameInTypeBeat];
scale.y = 1 / xFrames[frameInTypeBeat];
capsule.scale.x = xFrames[frameInTypeBeat];
capsule.scale.y = 1 / xFrames[frameInTypeBeat];
x = FlxG.width * xPosLerpLol[Std.int(Math.min(frameInTypeBeat, xPosLerpLol.length - 1))];
capsule.scale.x *= realScaled;
capsule.scale.y *= realScaled;
frameInTypeBeat += 1;
}
}
@ -89,10 +294,13 @@ class SongMenuItem extends FlxSpriteGroup
{
frameOutTicker = 0;
scale.x = xFrames[frameOutTypeBeat];
scale.y = 1 / xFrames[frameOutTypeBeat];
capsule.scale.x = xFrames[frameOutTypeBeat];
capsule.scale.y = 1 / xFrames[frameOutTypeBeat];
x = FlxG.width * xPosOutLerpLol[Std.int(Math.min(frameOutTypeBeat, xPosOutLerpLol.length - 1))];
capsule.scale.x *= realScaled;
capsule.scale.y *= realScaled;
frameOutTypeBeat += 1;
}
}
@ -106,14 +314,29 @@ class SongMenuItem extends FlxSpriteGroup
super.update(elapsed);
}
public function intendedY(index:Int):Float
{
return (index * ((height * realScaled) + 10)) + 120;
}
/**
* Merely a helper function to call set_selected, to make sure that the alpha is correct on the rankings/selections
*/
public function selectedAlpha():Void
{
selected = selected;
}
function set_selected(value:Bool):Bool
{
// trace(value);
// cute one liners, lol!
diffGrayscale.setAmount(value ? 0 : 0.8);
songText.alpha = value ? 1 : 0.6;
songText.blurredText.visible = value ? true : false;
capsule.offset.x = value ? 0 : -5;
capsule.animation.play(value ? "selected" : "unselected");
ranking.alpha = value ? 1 : 0.7;
ranking.color = value ? 0xFFFFFFFF : 0xFFAAAAAA;
return value;
}
}

View file

@ -181,7 +181,7 @@ class PreciseInputManager extends FlxKeyManager<FlxKey, PreciseInputList>
updateKeyStates(key, true);
if (getInputByKey(key) ?.justPressed ?? false)
if (getInputByKey(key)?.justPressed ?? false)
{
onInputPressed.dispatch(
{
@ -203,7 +203,7 @@ class PreciseInputManager extends FlxKeyManager<FlxKey, PreciseInputList>
updateKeyStates(key, false);
if (getInputByKey(key) ?.justReleased ?? false)
if (getInputByKey(key)?.justReleased ?? false)
{
onInputReleased.dispatch(
{
@ -264,7 +264,7 @@ class PreciseInputList extends FlxKeyList
{
for (key in getKeysForDir(noteDir))
{
if (check(_preciseInputManager.getInputByKey(key) ?.ID)) return true;
if (check(_preciseInputManager.getInputByKey(key)?.ID)) return true;
}
return false;
}

View file

@ -511,41 +511,7 @@ class PlayState extends MusicBeatSubState
NoteSplash.buildSplashFrames();
// Returns null if the song failed to load or doesn't have the selected difficulty.
if (currentSong == null || currentChart == null)
{
// We have encountered a critical error. Prevent Flixel from trying to run any gameplay logic.
criticalFailure = true;
// Choose an error message.
var message:String = 'There was a critical error. Click OK to return to the main menu.';
if (currentSong == null)
{
message = 'The was a critical error loading this song\'s chart. Click OK to return to the main menu.';
}
else if (currentDifficulty == null)
{
message = 'The was a critical error selecting a difficulty for this song. Click OK to return to the main menu.';
}
else if (currentSong.getDifficulty(currentDifficulty) == null)
{
message = 'The was a critical error retrieving data for this song on "$currentDifficulty" difficulty. Click OK to return to the main menu.';
}
// Display a popup. This blocks the application until the user clicks OK.
lime.app.Application.current.window.alert(message, 'Error loading PlayState');
// Force the user back to the main menu.
if (isSubState)
{
this.close();
}
else
{
FlxG.switchState(new MainMenuState());
}
return;
}
if (!assertChartExists()) return;
if (false)
{
@ -660,6 +626,47 @@ class PlayState extends MusicBeatSubState
initialized = true;
}
function assertChartExists():Bool
{
// Returns null if the song failed to load or doesn't have the selected difficulty.
if (currentSong == null || currentChart == null)
{
// We have encountered a critical error. Prevent Flixel from trying to run any gameplay logic.
criticalFailure = true;
// Choose an error message.
var message:String = 'There was a critical error. Click OK to return to the main menu.';
if (currentSong == null)
{
message = 'The was a critical error loading this song\'s chart. Click OK to return to the main menu.';
}
else if (currentDifficulty == null)
{
message = 'The was a critical error selecting a difficulty for this song. Click OK to return to the main menu.';
}
else if (currentSong.getDifficulty(currentDifficulty) == null)
{
message = 'The was a critical error retrieving data for this song on "$currentDifficulty" difficulty. Click OK to return to the main menu.';
}
// Display a popup. This blocks the application until the user clicks OK.
lime.app.Application.current.window.alert(message, 'Error loading PlayState');
// Force the user back to the main menu.
if (isSubState)
{
this.close();
}
else
{
FlxG.switchState(new MainMenuState());
}
return false;
}
return true;
}
public override function update(elapsed:Float):Void
{
if (criticalFailure) return;
@ -672,6 +679,8 @@ class PlayState extends MusicBeatSubState
// Handle restarting the song when needed (player death or pressing Retry)
if (needsReset)
{
if (!assertChartExists()) return;
dispatchEvent(new ScriptEvent(ScriptEvent.SONG_RETRY));
resetCamera();
@ -686,8 +695,10 @@ class PlayState extends MusicBeatSubState
// Reset music properly.
FlxG.sound.music.pause();
vocals.pause();
FlxG.sound.music.time = (startTimestamp);
vocals = currentChart.buildVocals();
vocals.pause();
vocals.time = 0;
FlxG.sound.music.volume = 1;

View file

@ -649,16 +649,20 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
}
boppers = [];
for (sprite in this.group)
if (group != null)
{
if (sprite != null)
for (sprite in this.group)
{
sprite.kill();
sprite.destroy();
remove(sprite);
if (sprite != null)
{
sprite.kill();
sprite.destroy();
remove(sprite);
}
}
group.clear();
}
group.clear();
if (debugIconGroup != null && debugIconGroup.group != null)
{
debugIconGroup.kill();

View file

@ -0,0 +1,23 @@
package funkin.shaderslmfao;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
import openfl.display.BitmapData;
class BlendModesShader extends FlxRuntimeShader
{
public var camera:BitmapData;
public function new()
{
super(Assets.getText(Paths.frag('blendModes')));
}
public function setCamera(camera:BitmapData):Void
{
this.camera = camera;
this.setBitmapData('camera', camera);
}
}

View file

@ -0,0 +1,25 @@
package funkin.shaderslmfao;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
/**
* Note... not actually gaussian!
*/
class GaussianBlurShader extends FlxRuntimeShader
{
public var amount:Float;
public function new(amount:Float = 1.0)
{
super(Assets.getText(Paths.frag("gaussianBlur")));
setAmount(amount);
}
public function setAmount(value:Float):Void
{
this.amount = value;
this.setFloat("amount", amount);
}
}

View file

@ -0,0 +1,22 @@
package funkin.shaderslmfao;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
class Grayscale extends FlxRuntimeShader
{
public var amount:Float = 1;
public function new(amount:Float = 1)
{
super(Assets.getText(Paths.frag("grayscale")));
setAmount(amount);
}
public function setAmount(value:Float):Void
{
amount = value;
this.setFloat("amount", amount);
}
}

View file

@ -0,0 +1,44 @@
package funkin.shaderslmfao;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
class HSVShader extends FlxRuntimeShader
{
public var hue(default, set):Float;
public var saturation(default, set):Float;
public var value(default, set):Float;
public function new()
{
super(Assets.getText(Paths.frag('hsv')));
hue = 1;
saturation = 1;
value = 1;
}
function set_hue(value:Float):Float
{
this.setFloat('hue', value);
this.hue = value;
return this.hue;
}
function set_saturation(value:Float):Float
{
this.setFloat('sat', value);
this.saturation = value;
return this.saturation;
}
function set_value(value:Float):Float
{
this.setFloat('val', value);
this.value = value;
return this.value;
}
}

View file

@ -0,0 +1,74 @@
package funkin.ui.title;
import flixel.FlxSprite;
import funkin.shaderslmfao.BlendModesShader;
import openfl.display.BitmapData;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.graphics.frames.FlxFrame.FlxFrameAngle;
class FlxSpriteOverlay extends FlxSprite
{
var blendShader:BlendModesShader;
var dipshitBitmap:BitmapData;
var temp:FlxSprite;
public function new(x:Float, y:Float)
{
super(x, y);
temp = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, 0xFF000000);
blendShader = new BlendModesShader();
dipshitBitmap = new BitmapData(2180, 1720, true, 0xFFCC00CC);
}
override function drawComplex(camera:FlxCamera):Void
{
_frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, checkFlipX(), checkFlipY());
_matrix.translate(-origin.x, -origin.y);
_matrix.scale(scale.x, scale.y);
if (bakedRotationAngle <= 0)
{
updateTrig();
if (angle != 0) _matrix.rotateWithTrig(_cosAngle, _sinAngle);
}
getScreenPosition(_point, camera).subtractPoint(offset);
_point.add(origin.x, origin.y);
_matrix.translate(_point.x, _point.y);
if (isPixelPerfectRender(camera))
{
_matrix.tx = Math.floor(_matrix.tx);
_matrix.ty = Math.floor(_matrix.ty);
}
var sprRect = getScreenBounds();
// dipshitBitmap.draw(camera.canvas, camera.canvas.transform.matrix);
// blendShader.setCamera(dipshitBitmap);
// FlxG.bitmapLog.add(dipshitBitmap);
camera.drawPixels(_frame, framePixels, _matrix, colorTransform, blend, antialiasing, shader);
}
function copyToFlash(rect):openfl.geom.Rectangle
{
var flashRect = new openfl.geom.Rectangle();
flashRect.x = rect.x;
flashRect.y = rect.y;
flashRect.width = rect.width;
flashRect.height = rect.height;
return flashRect;
}
override public function isSimpleRender(?camera:FlxCamera):Bool
{
if (FlxG.renderBlit)
{
return super.isSimpleRender(camera);
}
else
{
return false;
}
}
}

View file

@ -23,6 +23,7 @@ import openfl.events.MouseEvent;
import openfl.events.NetStatusEvent;
import openfl.media.Video;
import openfl.net.NetStream;
import openfl.display.BlendMode;
#if desktop
#end
@ -101,7 +102,7 @@ class TitleState extends MusicBeatState
var logoBl:FlxSprite;
var outlineShaderShit:TitleOutline;
var gfDance:FlxSprite;
var gfDance:FlxSpriteOverlay;
var danceLeft:Bool = false;
var titleText:FlxSprite;
var maskShader = new LeftMaskShader();
@ -124,13 +125,11 @@ class TitleState extends MusicBeatState
outlineShaderShit = new TitleOutline();
gfDance = new FlxSprite(FlxG.width * 0.4, FlxG.height * 0.07);
gfDance = new FlxSpriteOverlay(FlxG.width * 0.4, FlxG.height * 0.07);
gfDance.frames = Paths.getSparrowAtlas('gfDanceTitle');
gfDance.animation.addByIndices('danceLeft', 'gfDance', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
gfDance.animation.addByIndices('danceRight', 'gfDance', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
add(gfDance);
// maskShader.swagSprX = gfDance.x;
// maskShader.swagMaskX = gfDance.x + 200;
// maskShader.frameUV = gfDance.frame.uv;
@ -142,6 +141,8 @@ class TitleState extends MusicBeatState
add(logoBl);
add(gfDance);
titleText = new FlxSprite(100, FlxG.height * 0.8);
titleText.frames = Paths.getSparrowAtlas('titleEnter');
titleText.animation.addByPrefix('idle', "Press Enter to Begin", 24);
@ -245,6 +246,8 @@ class TitleState extends MusicBeatState
override function update(elapsed:Float)
{
FlxG.bitmapLog.add(FlxG.camera.buffer);
#if HAS_PITCH
if (FlxG.keys.pressed.UP) FlxG.sound.music.pitch += 0.5 * elapsed;