mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-27 10:05:41 -05:00
1277 lines
30 KiB
Haxe
1277 lines
30 KiB
Haxe
package;
|
|
|
|
import Section.SwagSection;
|
|
import Song.SwagSong;
|
|
import flixel.FlxBasic;
|
|
import flixel.FlxCamera;
|
|
import flixel.FlxG;
|
|
import flixel.FlxGame;
|
|
import flixel.FlxObject;
|
|
import flixel.FlxSprite;
|
|
import flixel.FlxState;
|
|
import flixel.FlxSubState;
|
|
import flixel.addons.display.FlxGridOverlay;
|
|
import flixel.addons.transition.FlxTransitionableState;
|
|
import flixel.graphics.atlas.FlxAtlas;
|
|
import flixel.graphics.frames.FlxAtlasFrames;
|
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
|
import flixel.math.FlxMath;
|
|
import flixel.math.FlxPoint;
|
|
import flixel.system.FlxSound;
|
|
import flixel.text.FlxText;
|
|
import flixel.tweens.FlxEase;
|
|
import flixel.tweens.FlxTween;
|
|
import flixel.ui.FlxBar;
|
|
import flixel.util.FlxCollision;
|
|
import flixel.util.FlxColor;
|
|
import flixel.util.FlxSort;
|
|
import flixel.util.FlxStringUtil;
|
|
import flixel.util.FlxTimer;
|
|
import haxe.Json;
|
|
import lime.utils.Assets;
|
|
|
|
using StringTools;
|
|
|
|
class PlayState extends MusicBeatState
|
|
{
|
|
public static var curLevel:String = 'Tutorial';
|
|
public static var SONG:SwagSong;
|
|
public static var isStoryMode:Bool = false;
|
|
public static var storyPlaylist:Array<String> = [];
|
|
|
|
var halloweenLevel:Bool = false;
|
|
|
|
private var vocals:FlxSound;
|
|
|
|
private var dad:Character;
|
|
private var gf:Character;
|
|
private var boyfriend:Boyfriend;
|
|
|
|
private var notes:FlxTypedGroup<Note>;
|
|
private var unspawnNotes:Array<Note> = [];
|
|
|
|
private var strumLine:FlxSprite;
|
|
private var curSection:Int = 0;
|
|
|
|
private var camFollow:FlxObject;
|
|
private var strumLineNotes:FlxTypedGroup<FlxSprite>;
|
|
private var playerStrums:FlxTypedGroup<FlxSprite>;
|
|
|
|
private var camZooming:Bool = false;
|
|
private var curSong:String = "";
|
|
|
|
private var gfSpeed:Int = 1;
|
|
private var health:Float = 1;
|
|
private var combo:Int = 0;
|
|
|
|
private var healthBarBG:FlxSprite;
|
|
private var healthBar:FlxBar;
|
|
|
|
private var generatedMusic:Bool = false;
|
|
private var startingSong:Bool = false;
|
|
|
|
private var healthHeads:FlxSprite;
|
|
private var camHUD:FlxCamera;
|
|
private var camGame:FlxCamera;
|
|
|
|
var dialogue:Array<String> = ['blah blah blah', 'coolswag'];
|
|
|
|
var halloweenBG:FlxSprite;
|
|
|
|
var talking:Bool = true;
|
|
|
|
override public function create()
|
|
{
|
|
// var gameCam:FlxCamera = FlxG.camera;
|
|
camGame = new FlxCamera();
|
|
camHUD = new FlxCamera();
|
|
camHUD.bgColor.alpha = 0;
|
|
|
|
FlxG.cameras.reset(camGame);
|
|
FlxG.cameras.add(camHUD);
|
|
|
|
FlxCamera.defaultCameras = [camGame];
|
|
|
|
persistentUpdate = true;
|
|
persistentDraw = true;
|
|
|
|
if (SONG == null)
|
|
SONG = Song.loadFromJson(curLevel);
|
|
|
|
Conductor.changeBPM(SONG.bpm);
|
|
|
|
switch (SONG.song.toLowerCase())
|
|
{
|
|
case 'tutorial':
|
|
dialogue = ["Hey you're pretty cute.", 'Use the arrow keys to keep up \nwith me singing.'];
|
|
case 'bopeebo':
|
|
dialogue = [
|
|
'HEY!',
|
|
"You think you can just sing\nwith my daughter like that?",
|
|
"If you want to date her...",
|
|
"You're going to have to go \nthrough ME first!"
|
|
];
|
|
}
|
|
|
|
if (SONG.song.toLowerCase() == 'spookeez' || SONG.song.toLowerCase() == 'monster' || SONG.song.toLowerCase() == 'south')
|
|
{
|
|
halloweenLevel = true;
|
|
|
|
var hallowTex = FlxAtlasFrames.fromSparrow(AssetPaths.halloween_bg__png, AssetPaths.halloween_bg__xml);
|
|
|
|
halloweenBG = new FlxSprite(-200, -100);
|
|
halloweenBG.frames = hallowTex;
|
|
halloweenBG.animation.addByPrefix('idle', 'halloweem bg0');
|
|
halloweenBG.animation.addByPrefix('lightning', 'halloweem bg lightning strike', 24, false);
|
|
halloweenBG.animation.play('idle');
|
|
halloweenBG.antialiasing = true;
|
|
add(halloweenBG);
|
|
}
|
|
else
|
|
{
|
|
var bg:FlxSprite = new FlxSprite(-600, -200).loadGraphic(AssetPaths.stageback__png);
|
|
// bg.setGraphicSize(Std.int(bg.width * 2.5));
|
|
// bg.updateHitbox();
|
|
bg.antialiasing = true;
|
|
bg.scrollFactor.set(0.9, 0.9);
|
|
bg.active = false;
|
|
add(bg);
|
|
|
|
var stageFront:FlxSprite = new FlxSprite(-650, 600).loadGraphic(AssetPaths.stagefront__png);
|
|
stageFront.setGraphicSize(Std.int(stageFront.width * 1.1));
|
|
stageFront.updateHitbox();
|
|
stageFront.antialiasing = true;
|
|
stageFront.scrollFactor.set(0.9, 0.9);
|
|
stageFront.active = false;
|
|
add(stageFront);
|
|
|
|
var stageCurtains:FlxSprite = new FlxSprite(-500, -300).loadGraphic(AssetPaths.stagecurtains__png);
|
|
stageCurtains.setGraphicSize(Std.int(stageCurtains.width * 0.9));
|
|
stageCurtains.updateHitbox();
|
|
stageCurtains.antialiasing = true;
|
|
stageCurtains.scrollFactor.set(1.3, 1.3);
|
|
stageCurtains.active = false;
|
|
|
|
add(stageCurtains);
|
|
}
|
|
|
|
gf = new Character(400, 130, 'gf');
|
|
gf.scrollFactor.set(0.95, 0.95);
|
|
gf.antialiasing = true;
|
|
add(gf);
|
|
|
|
dad = new Character(100, 100, SONG.player2);
|
|
add(dad);
|
|
|
|
var camPos:FlxPoint = new FlxPoint(dad.getGraphicMidpoint().x, dad.getGraphicMidpoint().y);
|
|
|
|
switch (SONG.player2)
|
|
{
|
|
case 'gf':
|
|
dad.setPosition(gf.x, gf.y);
|
|
gf.visible = false;
|
|
if (isStoryMode)
|
|
{
|
|
camPos.x += 600;
|
|
tweenCamIn();
|
|
}
|
|
|
|
case "spooky":
|
|
dad.y += 200;
|
|
case "monster":
|
|
dad.y += 100;
|
|
case 'dad':
|
|
camPos.x += 400;
|
|
}
|
|
|
|
boyfriend = new Boyfriend(770, 450);
|
|
add(boyfriend);
|
|
|
|
var doof:DialogueBox = new DialogueBox(false, dialogue);
|
|
// doof.x += 70;
|
|
doof.y = FlxG.height * 0.5;
|
|
doof.scrollFactor.set();
|
|
doof.finishThing = startCountdown;
|
|
|
|
Conductor.songPosition = -5000;
|
|
|
|
strumLine = new FlxSprite(0, 50).makeGraphic(FlxG.width, 10);
|
|
strumLine.scrollFactor.set();
|
|
|
|
strumLineNotes = new FlxTypedGroup<FlxSprite>();
|
|
add(strumLineNotes);
|
|
|
|
playerStrums = new FlxTypedGroup<FlxSprite>();
|
|
|
|
startingSong = true;
|
|
|
|
// startCountdown();
|
|
|
|
generateSong(SONG.song);
|
|
|
|
// add(strumLine);
|
|
|
|
camFollow = new FlxObject(0, 0, 1, 1);
|
|
|
|
camFollow.setPosition(camPos.x, camPos.y);
|
|
add(camFollow);
|
|
|
|
FlxG.camera.follow(camFollow, LOCKON, 0.04);
|
|
// FlxG.camera.setScrollBounds(0, FlxG.width, 0, FlxG.height);
|
|
FlxG.camera.zoom = 1.05;
|
|
|
|
FlxG.worldBounds.set(0, 0, FlxG.width, FlxG.height);
|
|
|
|
FlxG.fixedTimestep = false;
|
|
|
|
healthBarBG = new FlxSprite(0, FlxG.height * 0.9).loadGraphic(AssetPaths.healthBar__png);
|
|
healthBarBG.screenCenter(X);
|
|
healthBarBG.scrollFactor.set();
|
|
add(healthBarBG);
|
|
|
|
healthBar = new FlxBar(healthBarBG.x + 4, healthBarBG.y + 4, RIGHT_TO_LEFT, Std.int(healthBarBG.width - 8), Std.int(healthBarBG.height - 8), this,
|
|
'health', 0, 2);
|
|
healthBar.scrollFactor.set();
|
|
healthBar.createFilledBar(0xFFFF0000, 0xFF66FF33);
|
|
// healthBar
|
|
add(healthBar);
|
|
|
|
healthHeads = new FlxSprite();
|
|
var headTex = FlxAtlasFrames.fromSparrow(AssetPaths.healthHeads__png, AssetPaths.healthHeads__xml);
|
|
healthHeads.frames = headTex;
|
|
healthHeads.animation.add('healthy', [0]);
|
|
healthHeads.animation.add('unhealthy', [1]);
|
|
healthHeads.y = healthBar.y - (healthHeads.height / 2);
|
|
healthHeads.scrollFactor.set();
|
|
healthHeads.antialiasing = true;
|
|
add(healthHeads);
|
|
|
|
// healthBar.visible = healthHeads.visible = healthBarBG.visible = false;
|
|
if (isStoryMode)
|
|
{
|
|
add(doof);
|
|
}
|
|
else
|
|
startCountdown();
|
|
|
|
strumLineNotes.cameras = [camHUD];
|
|
notes.cameras = [camHUD];
|
|
healthBar.cameras = [camHUD];
|
|
healthBarBG.cameras = [camHUD];
|
|
healthHeads.cameras = [camHUD];
|
|
doof.cameras = [camHUD];
|
|
|
|
// if (SONG.song == 'South')
|
|
// FlxG.camera.alpha = 0.7;
|
|
// UI_camera.zoom = 1;
|
|
|
|
// cameras = [FlxG.cameras.list[1]];
|
|
|
|
super.create();
|
|
}
|
|
|
|
var startTimer:FlxTimer;
|
|
|
|
function startCountdown():Void
|
|
{
|
|
generateStaticArrows(0);
|
|
generateStaticArrows(1);
|
|
|
|
talking = false;
|
|
startedCountdown = true;
|
|
Conductor.songPosition = 0;
|
|
Conductor.songPosition -= Conductor.crochet * 5;
|
|
|
|
var swagCounter:Int = 0;
|
|
|
|
startTimer = new FlxTimer().start(Conductor.crochet / 1000, function(tmr:FlxTimer)
|
|
{
|
|
dad.dance();
|
|
gf.dance();
|
|
boyfriend.playAnim('idle');
|
|
|
|
switch (swagCounter)
|
|
{
|
|
case 0:
|
|
FlxG.sound.play('assets/sounds/intro3' + TitleState.soundExt, 0.6);
|
|
case 1:
|
|
var ready:FlxSprite = new FlxSprite().loadGraphic('assets/images/ready.png');
|
|
ready.scrollFactor.set();
|
|
ready.screenCenter();
|
|
add(ready);
|
|
FlxTween.tween(ready, {y: ready.y += 100, alpha: 0}, Conductor.crochet / 1000, {
|
|
ease: FlxEase.cubeInOut,
|
|
onComplete: function(twn:FlxTween)
|
|
{
|
|
ready.destroy();
|
|
}
|
|
});
|
|
FlxG.sound.play('assets/sounds/intro2' + TitleState.soundExt, 0.6);
|
|
case 2:
|
|
var set:FlxSprite = new FlxSprite().loadGraphic('assets/images/set.png');
|
|
set.scrollFactor.set();
|
|
set.screenCenter();
|
|
add(set);
|
|
FlxTween.tween(set, {y: set.y += 100, alpha: 0}, Conductor.crochet / 1000, {
|
|
ease: FlxEase.cubeInOut,
|
|
onComplete: function(twn:FlxTween)
|
|
{
|
|
set.destroy();
|
|
}
|
|
});
|
|
FlxG.sound.play('assets/sounds/intro1' + TitleState.soundExt, 0.6);
|
|
case 3:
|
|
var go:FlxSprite = new FlxSprite().loadGraphic('assets/images/go.png');
|
|
go.scrollFactor.set();
|
|
go.screenCenter();
|
|
add(go);
|
|
FlxTween.tween(go, {y: go.y += 100, alpha: 0}, Conductor.crochet / 1000, {
|
|
ease: FlxEase.cubeInOut,
|
|
onComplete: function(twn:FlxTween)
|
|
{
|
|
go.destroy();
|
|
}
|
|
});
|
|
FlxG.sound.play('assets/sounds/introGo' + TitleState.soundExt, 0.6);
|
|
case 4:
|
|
}
|
|
|
|
swagCounter += 1;
|
|
// generateSong('fresh');
|
|
}, 5);
|
|
}
|
|
|
|
var previousFrameTime:Int = 0;
|
|
var lastReportedPlayheadPosition:Int = 0;
|
|
var songTime:Float = 0;
|
|
|
|
function startSong():Void
|
|
{
|
|
previousFrameTime = FlxG.game.ticks;
|
|
lastReportedPlayheadPosition = 0;
|
|
|
|
startingSong = false;
|
|
FlxG.sound.playMusic("assets/music/" + SONG.song + "_Inst" + TitleState.soundExt, 1, false);
|
|
FlxG.sound.music.onComplete = endSong;
|
|
vocals.play();
|
|
}
|
|
|
|
var debugNum:Int = 0;
|
|
|
|
private function generateSong(dataPath:String):Void
|
|
{
|
|
// FlxG.log.add(ChartParser.parse());
|
|
|
|
var songData = SONG;
|
|
Conductor.changeBPM(songData.bpm);
|
|
|
|
curSong = songData.song;
|
|
|
|
if (SONG.needsVoices)
|
|
vocals = new FlxSound().loadEmbedded("assets/music/" + curSong + "_Voices" + TitleState.soundExt);
|
|
else
|
|
vocals = new FlxSound();
|
|
|
|
FlxG.sound.list.add(vocals);
|
|
|
|
notes = new FlxTypedGroup<Note>();
|
|
add(notes);
|
|
|
|
var noteData:Array<SwagSection>;
|
|
|
|
// NEW SHIT
|
|
noteData = songData.notes;
|
|
|
|
var playerCounter:Int = 0;
|
|
|
|
var daBeats:Int = 0; // Not exactly representative of 'daBeats' lol, just how much it has looped
|
|
for (section in noteData)
|
|
{
|
|
var coolSection:Int = Std.int(section.lengthInSteps / 4);
|
|
|
|
for (songNotes in section.sectionNotes)
|
|
{
|
|
var daStrumTime:Float = songNotes[0];
|
|
var daNoteData:Int = Std.int(songNotes[1] % 4);
|
|
|
|
var gottaHitNote:Bool = section.mustHitSection;
|
|
|
|
if (songNotes[1] > 3)
|
|
{
|
|
gottaHitNote = !section.mustHitSection;
|
|
}
|
|
|
|
var oldNote:Note;
|
|
if (unspawnNotes.length > 0)
|
|
oldNote = unspawnNotes[Std.int(unspawnNotes.length - 1)];
|
|
else
|
|
oldNote = null;
|
|
|
|
var swagNote:Note = new Note(daStrumTime, daNoteData, oldNote);
|
|
swagNote.sustainLength = songNotes[2];
|
|
swagNote.scrollFactor.set(0, 0);
|
|
|
|
var susLength:Float = swagNote.sustainLength;
|
|
|
|
susLength = susLength / Conductor.stepCrochet;
|
|
unspawnNotes.push(swagNote);
|
|
|
|
for (susNote in 0...Math.floor(susLength))
|
|
{
|
|
oldNote = unspawnNotes[Std.int(unspawnNotes.length - 1)];
|
|
|
|
var sustainNote:Note = new Note(daStrumTime + (Conductor.stepCrochet * susNote) + Conductor.stepCrochet, daNoteData, oldNote, true);
|
|
sustainNote.scrollFactor.set();
|
|
unspawnNotes.push(sustainNote);
|
|
|
|
sustainNote.mustPress = gottaHitNote;
|
|
|
|
if (sustainNote.mustPress)
|
|
{
|
|
sustainNote.x += FlxG.width / 2; // general offset
|
|
}
|
|
}
|
|
|
|
swagNote.mustPress = gottaHitNote;
|
|
|
|
if (swagNote.mustPress)
|
|
{
|
|
swagNote.x += FlxG.width / 2; // general offset
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
daBeats += 1;
|
|
}
|
|
|
|
trace(unspawnNotes.length);
|
|
// playerCounter += 1;
|
|
|
|
unspawnNotes.sort(sortByShit);
|
|
|
|
generatedMusic = true;
|
|
}
|
|
|
|
function sortByShit(Obj1:Note, Obj2:Note):Int
|
|
{
|
|
return FlxSort.byValues(FlxSort.ASCENDING, Obj1.strumTime, Obj2.strumTime);
|
|
}
|
|
|
|
private function generateStaticArrows(player:Int):Void
|
|
{
|
|
for (i in 0...4)
|
|
{
|
|
FlxG.log.add(i);
|
|
var babyArrow:FlxSprite = new FlxSprite(0, strumLine.y);
|
|
var arrTex = FlxAtlasFrames.fromSparrow(AssetPaths.NOTE_assets__png, AssetPaths.NOTE_assets__xml);
|
|
babyArrow.frames = arrTex;
|
|
babyArrow.animation.addByPrefix('green', 'arrowUP');
|
|
babyArrow.animation.addByPrefix('blue', 'arrowDOWN');
|
|
babyArrow.animation.addByPrefix('purple', 'arrowLEFT');
|
|
babyArrow.animation.addByPrefix('red', 'arrowRIGHT');
|
|
|
|
babyArrow.scrollFactor.set();
|
|
babyArrow.setGraphicSize(Std.int(babyArrow.width * 0.7));
|
|
babyArrow.updateHitbox();
|
|
babyArrow.antialiasing = true;
|
|
|
|
babyArrow.y -= 10;
|
|
babyArrow.alpha = 0;
|
|
FlxTween.tween(babyArrow, {y: babyArrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * i)});
|
|
|
|
babyArrow.ID = i;
|
|
|
|
if (player == 1)
|
|
{
|
|
playerStrums.add(babyArrow);
|
|
}
|
|
|
|
switch (Math.abs(i))
|
|
{
|
|
case 2:
|
|
babyArrow.x += Note.swagWidth * 2;
|
|
babyArrow.animation.addByPrefix('static', 'arrowUP');
|
|
babyArrow.animation.addByPrefix('pressed', 'up press', 24, false);
|
|
babyArrow.animation.addByPrefix('confirm', 'up confirm', 24, false);
|
|
case 3:
|
|
babyArrow.x += Note.swagWidth * 3;
|
|
babyArrow.animation.addByPrefix('static', 'arrowRIGHT');
|
|
babyArrow.animation.addByPrefix('pressed', 'right press', 24, false);
|
|
babyArrow.animation.addByPrefix('confirm', 'right confirm', 24, false);
|
|
case 1:
|
|
babyArrow.x += Note.swagWidth * 1;
|
|
babyArrow.animation.addByPrefix('static', 'arrowDOWN');
|
|
babyArrow.animation.addByPrefix('pressed', 'down press', 24, false);
|
|
babyArrow.animation.addByPrefix('confirm', 'down confirm', 24, false);
|
|
case 0:
|
|
babyArrow.x += Note.swagWidth * 0;
|
|
babyArrow.animation.addByPrefix('static', 'arrowLEFT');
|
|
babyArrow.animation.addByPrefix('pressed', 'left press', 24, false);
|
|
babyArrow.animation.addByPrefix('confirm', 'left confirm', 24, false);
|
|
}
|
|
|
|
babyArrow.animation.play('static');
|
|
babyArrow.x += 50;
|
|
babyArrow.x += ((FlxG.width / 2) * player);
|
|
|
|
strumLineNotes.add(babyArrow);
|
|
}
|
|
}
|
|
|
|
function tweenCamIn():Void
|
|
{
|
|
FlxTween.tween(FlxG.camera, {zoom: 1.3}, (Conductor.stepCrochet * 4 / 1000), {ease: FlxEase.elasticInOut});
|
|
}
|
|
|
|
override function openSubState(SubState:FlxSubState)
|
|
{
|
|
if (paused)
|
|
{
|
|
if (FlxG.sound.music != null)
|
|
{
|
|
FlxG.sound.music.pause();
|
|
vocals.pause();
|
|
}
|
|
|
|
if (!startTimer.finished)
|
|
startTimer.active = false;
|
|
}
|
|
|
|
super.openSubState(SubState);
|
|
}
|
|
|
|
override function closeSubState()
|
|
{
|
|
if (paused)
|
|
{
|
|
if (FlxG.sound.music != null)
|
|
{
|
|
vocals.time = FlxG.sound.music.time;
|
|
|
|
FlxG.sound.music.play();
|
|
vocals.play();
|
|
}
|
|
|
|
if (!startTimer.finished)
|
|
startTimer.active = true;
|
|
paused = false;
|
|
}
|
|
|
|
super.closeSubState();
|
|
}
|
|
|
|
private var paused:Bool = false;
|
|
var startedCountdown:Bool = false;
|
|
|
|
override public function update(elapsed:Float)
|
|
{
|
|
super.update(elapsed);
|
|
|
|
// trace("SONG POS: " + Conductor.songPosition);
|
|
// FlxG.sound.music.pitch = 2;
|
|
|
|
if (FlxG.keys.justPressed.ENTER && startedCountdown)
|
|
{
|
|
persistentUpdate = false;
|
|
persistentDraw = true;
|
|
paused = true;
|
|
|
|
openSubState(new PauseSubState(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y));
|
|
}
|
|
|
|
if (FlxG.keys.justPressed.ESCAPE)
|
|
{
|
|
FlxG.switchState(new ChartingState());
|
|
}
|
|
|
|
// FlxG.watch.addQuick('VOL', vocals.amplitudeLeft);
|
|
// FlxG.watch.addQuick('VOLRight', vocals.amplitudeRight);
|
|
|
|
healthHeads.setGraphicSize(Std.int(FlxMath.lerp(100, healthHeads.width, 0.98)));
|
|
healthHeads.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 100, 0) * 0.01)) - (healthHeads.width / 2);
|
|
|
|
if (healthBar.percent < 20)
|
|
healthHeads.animation.play('unhealthy');
|
|
else
|
|
healthHeads.animation.play('healthy');
|
|
|
|
/* if (FlxG.keys.justPressed.NINE)
|
|
FlxG.switchState(new Charting()); */
|
|
if (FlxG.keys.justPressed.EIGHT)
|
|
FlxG.switchState(new AnimationDebug(SONG.player2));
|
|
|
|
if (startingSong)
|
|
{
|
|
if (startedCountdown)
|
|
{
|
|
Conductor.songPosition += FlxG.elapsed * 1000;
|
|
if (Conductor.songPosition >= 0)
|
|
startSong();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Conductor.songPosition = FlxG.sound.music.time;
|
|
|
|
if (!paused)
|
|
{
|
|
songTime += FlxG.game.ticks - previousFrameTime;
|
|
previousFrameTime = FlxG.game.ticks;
|
|
|
|
// Interpolation type beat
|
|
if (Conductor.lastSongPos != Conductor.songPosition)
|
|
{
|
|
songTime = (songTime + Conductor.songPosition) / 2;
|
|
Conductor.lastSongPos = Conductor.songPosition;
|
|
// Conductor.songPosition += FlxG.elapsed * 1000;
|
|
// trace('MISSED FRAME');
|
|
}
|
|
}
|
|
|
|
// Conductor.lastSongPos = FlxG.sound.music.time;
|
|
}
|
|
|
|
if (generatedMusic && PlayState.SONG.notes[Std.int(curStep / 16)] != null)
|
|
{
|
|
if (curBeat % 4 == 0)
|
|
{
|
|
// trace(PlayState.SONG.notes[Std.int(curStep / 16)].mustHitSection);
|
|
}
|
|
|
|
if (camFollow.x != dad.getMidpoint().x + 150 && !PlayState.SONG.notes[Std.int(curStep / 16)].mustHitSection)
|
|
{
|
|
camFollow.setPosition(dad.getMidpoint().x + 150, dad.getMidpoint().y - 100);
|
|
vocals.volume = 1;
|
|
|
|
if (SONG.song.toLowerCase() == 'tutorial')
|
|
{
|
|
tweenCamIn();
|
|
}
|
|
}
|
|
|
|
if (PlayState.SONG.notes[Std.int(curStep / 16)].mustHitSection && camFollow.x != boyfriend.getMidpoint().x - 100)
|
|
{
|
|
camFollow.setPosition(boyfriend.getMidpoint().x - 100, boyfriend.getMidpoint().y - 100);
|
|
|
|
if (SONG.song.toLowerCase() == 'tutorial')
|
|
{
|
|
FlxTween.tween(FlxG.camera, {zoom: 1}, (Conductor.stepCrochet * 4 / 1000), {ease: FlxEase.elasticInOut});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (camZooming)
|
|
{
|
|
FlxG.camera.zoom = FlxMath.lerp(1.05, FlxG.camera.zoom, 0.96);
|
|
}
|
|
|
|
FlxG.watch.addQuick("beatShit", totalBeats);
|
|
|
|
if (curSong == 'Fresh')
|
|
{
|
|
switch (totalBeats)
|
|
{
|
|
case 16:
|
|
camZooming = true;
|
|
gfSpeed = 2;
|
|
case 48:
|
|
gfSpeed = 1;
|
|
case 80:
|
|
gfSpeed = 2;
|
|
case 112:
|
|
gfSpeed = 1;
|
|
case 163:
|
|
// FlxG.sound.music.stop();
|
|
// curLevel = 'Bopeebo';
|
|
// FlxG.switchState(new TitleState());
|
|
}
|
|
}
|
|
|
|
if (curSong == 'Bopeebo')
|
|
{
|
|
switch (totalBeats)
|
|
{
|
|
case 127:
|
|
// FlxG.sound.music.stop();
|
|
// curLevel = 'Fresh';
|
|
// FlxG.switchState(new PlayState());
|
|
}
|
|
}
|
|
// better streaming of shit
|
|
|
|
if (health <= 0)
|
|
{
|
|
boyfriend.stunned = true;
|
|
|
|
persistentUpdate = false;
|
|
persistentDraw = false;
|
|
paused = true;
|
|
|
|
vocals.stop();
|
|
FlxG.sound.music.stop();
|
|
|
|
openSubState(new GameOverSubstate(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y));
|
|
|
|
// FlxG.switchState(new GameOverState(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y));
|
|
}
|
|
|
|
if (unspawnNotes[0] != null)
|
|
{
|
|
if (unspawnNotes[0].strumTime - Conductor.songPosition < 1500)
|
|
{
|
|
var dunceNote:Note = unspawnNotes[0];
|
|
notes.add(dunceNote);
|
|
|
|
var index:Int = unspawnNotes.indexOf(dunceNote);
|
|
unspawnNotes.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
if (generatedMusic)
|
|
{
|
|
notes.forEachAlive(function(daNote:Note)
|
|
{
|
|
if (daNote.y > FlxG.height)
|
|
{
|
|
daNote.active = false;
|
|
daNote.visible = false;
|
|
}
|
|
else
|
|
{
|
|
daNote.visible = true;
|
|
daNote.active = true;
|
|
}
|
|
|
|
if (!daNote.mustPress && daNote.wasGoodHit)
|
|
{
|
|
switch (Math.abs(daNote.noteData))
|
|
{
|
|
case 2:
|
|
dad.playAnim('singUP', true);
|
|
case 3:
|
|
dad.playAnim('singRIGHT', true);
|
|
case 1:
|
|
dad.playAnim('singDOWN', true);
|
|
case 0:
|
|
dad.playAnim('singLEFT', true);
|
|
}
|
|
|
|
if (SONG.needsVoices)
|
|
vocals.volume = 1;
|
|
|
|
daNote.kill();
|
|
notes.remove(daNote, true);
|
|
daNote.destroy();
|
|
}
|
|
|
|
daNote.y = (strumLine.y - (Conductor.songPosition - daNote.strumTime) * (0.45 * PlayState.SONG.speed));
|
|
// WIP interpolation shit? Need to fix the pause issue
|
|
// daNote.y = (strumLine.y - (songTime - daNote.strumTime) * (0.45 * PlayState.SONG.speed));
|
|
|
|
if (daNote.y < -daNote.height)
|
|
{
|
|
if (daNote.tooLate)
|
|
{
|
|
health -= 0.03;
|
|
vocals.volume = 0;
|
|
}
|
|
|
|
daNote.active = false;
|
|
daNote.visible = false;
|
|
|
|
daNote.kill();
|
|
notes.remove(daNote, true);
|
|
daNote.destroy();
|
|
}
|
|
});
|
|
}
|
|
|
|
keyShit();
|
|
}
|
|
|
|
function endSong():Void
|
|
{
|
|
trace('SONG DONE' + isStoryMode);
|
|
|
|
if (isStoryMode)
|
|
{
|
|
storyPlaylist.remove(storyPlaylist[0]);
|
|
|
|
if (storyPlaylist.length <= 0)
|
|
{
|
|
FlxG.switchState(new TitleState());
|
|
|
|
StoryMenuState.weekUnlocked[1] = true;
|
|
}
|
|
else
|
|
{
|
|
PlayState.SONG = Song.loadFromJson(PlayState.storyPlaylist[0].toLowerCase());
|
|
FlxG.switchState(new PlayState());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FlxG.switchState(new FreeplayState());
|
|
}
|
|
}
|
|
|
|
var endingSong:Bool = false;
|
|
|
|
private function popUpScore(strumtime:Float):Void
|
|
{
|
|
var noteDiff:Float = Math.abs(strumtime - Conductor.songPosition);
|
|
// boyfriend.playAnim('hey');
|
|
vocals.volume = 1;
|
|
|
|
var placement:String = Std.string(combo);
|
|
|
|
var coolText:FlxText = new FlxText(0, 0, 0, placement, 32);
|
|
coolText.screenCenter();
|
|
coolText.x = FlxG.width * 0.55;
|
|
//
|
|
|
|
var rating:FlxSprite = new FlxSprite();
|
|
|
|
var daRating:String = "sick";
|
|
|
|
if (noteDiff > Conductor.safeZoneOffset * 0.9)
|
|
{
|
|
daRating = 'shit';
|
|
}
|
|
else if (noteDiff > Conductor.safeZoneOffset * 0.75)
|
|
{
|
|
daRating = 'bad';
|
|
}
|
|
else if (noteDiff > Conductor.safeZoneOffset * 0.2)
|
|
{
|
|
daRating = 'good';
|
|
}
|
|
|
|
/* if (combo > 60)
|
|
daRating = 'sick';
|
|
else if (combo > 12)
|
|
daRating = 'good'
|
|
else if (combo > 4)
|
|
daRating = 'bad';
|
|
*/
|
|
rating.loadGraphic('assets/images/' + daRating + ".png");
|
|
rating.screenCenter();
|
|
rating.x = coolText.x - 40;
|
|
rating.y -= 60;
|
|
rating.acceleration.y = 550;
|
|
rating.velocity.y -= FlxG.random.int(140, 175);
|
|
rating.setGraphicSize(Std.int(rating.width * 0.7));
|
|
rating.updateHitbox();
|
|
rating.antialiasing = true;
|
|
rating.velocity.x -= FlxG.random.int(0, 10);
|
|
|
|
var comboSpr:FlxSprite = new FlxSprite().loadGraphic(AssetPaths.combo__png);
|
|
comboSpr.screenCenter();
|
|
comboSpr.x = coolText.x;
|
|
comboSpr.acceleration.y = 600;
|
|
comboSpr.antialiasing = true;
|
|
comboSpr.velocity.y -= 150;
|
|
comboSpr.setGraphicSize(Std.int(comboSpr.width * 0.7));
|
|
comboSpr.updateHitbox();
|
|
comboSpr.velocity.x += FlxG.random.int(1, 10);
|
|
// add(comboSpr);
|
|
add(rating);
|
|
|
|
var seperatedScore:Array<Int> = [];
|
|
|
|
seperatedScore.push(Math.floor(combo / 100));
|
|
seperatedScore.push(Math.floor((combo - (seperatedScore[0] * 100)) / 10));
|
|
seperatedScore.push(combo % 10);
|
|
|
|
var daLoop:Int = 0;
|
|
for (i in seperatedScore)
|
|
{
|
|
var numScore:FlxSprite = new FlxSprite().loadGraphic('assets/images/num' + Std.int(i) + '.png');
|
|
numScore.screenCenter();
|
|
numScore.x = coolText.x + (43 * daLoop) - 90;
|
|
numScore.y += 80;
|
|
numScore.antialiasing = true;
|
|
numScore.setGraphicSize(Std.int(numScore.width * 0.5));
|
|
numScore.updateHitbox();
|
|
numScore.acceleration.y = FlxG.random.int(200, 300);
|
|
numScore.velocity.y -= FlxG.random.int(140, 160);
|
|
numScore.velocity.x = FlxG.random.float(-5, 5);
|
|
add(numScore);
|
|
|
|
FlxTween.tween(numScore, {alpha: 0}, 0.2, {
|
|
onComplete: function(tween:FlxTween)
|
|
{
|
|
numScore.destroy();
|
|
},
|
|
startDelay: Conductor.crochet * 0.002
|
|
});
|
|
|
|
daLoop++;
|
|
}
|
|
/*
|
|
trace(combo);
|
|
trace(seperatedScore);
|
|
*/
|
|
|
|
coolText.text = Std.string(seperatedScore);
|
|
// add(coolText);
|
|
|
|
FlxTween.tween(rating, {alpha: 0}, 0.2, {
|
|
startDelay: Conductor.crochet * 0.001
|
|
});
|
|
|
|
FlxTween.tween(comboSpr, {alpha: 0}, 0.2, {
|
|
onComplete: function(tween:FlxTween)
|
|
{
|
|
coolText.destroy();
|
|
comboSpr.destroy();
|
|
|
|
rating.destroy();
|
|
},
|
|
startDelay: Conductor.crochet * 0.001
|
|
});
|
|
|
|
curSection += 1;
|
|
}
|
|
|
|
private function keyShit():Void
|
|
{
|
|
// HOLDING
|
|
var up = controls.UP;
|
|
var right = controls.RIGHT;
|
|
var down = controls.DOWN;
|
|
var left = controls.LEFT;
|
|
|
|
var upP = controls.UP_P;
|
|
var rightP = controls.RIGHT_P;
|
|
var downP = controls.DOWN_P;
|
|
var leftP = controls.LEFT_P;
|
|
|
|
var upR = controls.UP_R;
|
|
var rightR = controls.RIGHT_R;
|
|
var downR = controls.DOWN_R;
|
|
var leftR = controls.LEFT_R;
|
|
|
|
// FlxG.watch.addQuick('asdfa', upP);
|
|
if ((upP || rightP || downP || leftP) && !boyfriend.stunned && generatedMusic)
|
|
{
|
|
var possibleNotes:Array<Note> = [];
|
|
|
|
notes.forEachAlive(function(daNote:Note)
|
|
{
|
|
if (daNote.canBeHit && daNote.mustPress && !daNote.tooLate)
|
|
{
|
|
possibleNotes.push(daNote);
|
|
trace('NOTE-' + daNote.strumTime + ' ADDED');
|
|
}
|
|
});
|
|
|
|
if (possibleNotes.length > 0)
|
|
{
|
|
for (daNote in possibleNotes)
|
|
{
|
|
switch (daNote.noteData)
|
|
{
|
|
case 2: // NOTES YOU JUST PRESSED
|
|
if (upP || rightP || downP || leftP)
|
|
noteCheck(upP, daNote);
|
|
case 3:
|
|
if (upP || rightP || downP || leftP)
|
|
noteCheck(rightP, daNote);
|
|
case 1:
|
|
if (upP || rightP || downP || leftP)
|
|
noteCheck(downP, daNote);
|
|
case 0:
|
|
if (upP || rightP || downP || leftP)
|
|
noteCheck(leftP, daNote);
|
|
}
|
|
|
|
if (daNote.wasGoodHit)
|
|
{
|
|
daNote.kill();
|
|
notes.remove(daNote, true);
|
|
daNote.destroy();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
badNoteCheck();
|
|
}
|
|
}
|
|
|
|
if ((up || right || down || left) && !boyfriend.stunned && generatedMusic)
|
|
{
|
|
notes.forEachAlive(function(daNote:Note)
|
|
{
|
|
if (daNote.canBeHit && daNote.mustPress && daNote.isSustainNote)
|
|
{
|
|
switch (daNote.noteData)
|
|
{
|
|
// NOTES YOU ARE HOLDING
|
|
case 2:
|
|
if (up && daNote.prevNote.wasGoodHit)
|
|
goodNoteHit(daNote);
|
|
case 3:
|
|
if (right && daNote.prevNote.wasGoodHit)
|
|
goodNoteHit(daNote);
|
|
case 1:
|
|
if (down && daNote.prevNote.wasGoodHit)
|
|
goodNoteHit(daNote);
|
|
case 0:
|
|
if (left && daNote.prevNote.wasGoodHit)
|
|
goodNoteHit(daNote);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (upR || leftR || rightR || downR)
|
|
{
|
|
if (boyfriend.animation.curAnim.name.startsWith('sing'))
|
|
{
|
|
boyfriend.playAnim('idle');
|
|
}
|
|
}
|
|
|
|
playerStrums.forEach(function(spr:FlxSprite)
|
|
{
|
|
switch (spr.ID)
|
|
{
|
|
case 2:
|
|
if (upP && spr.animation.curAnim.name != 'confirm')
|
|
spr.animation.play('pressed');
|
|
if (upR)
|
|
spr.animation.play('static');
|
|
case 3:
|
|
if (rightP && spr.animation.curAnim.name != 'confirm')
|
|
spr.animation.play('pressed');
|
|
if (rightR)
|
|
spr.animation.play('static');
|
|
case 1:
|
|
if (downP && spr.animation.curAnim.name != 'confirm')
|
|
spr.animation.play('pressed');
|
|
if (downR)
|
|
spr.animation.play('static');
|
|
case 0:
|
|
if (leftP && spr.animation.curAnim.name != 'confirm')
|
|
spr.animation.play('pressed');
|
|
if (leftR)
|
|
spr.animation.play('static');
|
|
}
|
|
|
|
if (spr.animation.curAnim.name == 'confirm')
|
|
{
|
|
spr.centerOffsets();
|
|
spr.offset.x -= 13;
|
|
spr.offset.y -= 13;
|
|
}
|
|
else
|
|
spr.centerOffsets();
|
|
});
|
|
}
|
|
|
|
function noteMiss(direction:Int = 1):Void
|
|
{
|
|
if (!boyfriend.stunned)
|
|
{
|
|
health -= 0.055;
|
|
if (combo > 5)
|
|
{
|
|
gf.playAnim('sad');
|
|
}
|
|
combo = 0;
|
|
|
|
FlxG.sound.play('assets/sounds/missnote' + FlxG.random.int(1, 3) + TitleState.soundExt, FlxG.random.float(0.1, 0.2));
|
|
// FlxG.sound.play('assets/sounds/missnote1' + TitleState.soundExt, 1, false);
|
|
// FlxG.log.add('played imss note');
|
|
|
|
boyfriend.stunned = true;
|
|
|
|
// get stunned for 5 seconds
|
|
new FlxTimer().start(5 / 60, function(tmr:FlxTimer)
|
|
{
|
|
boyfriend.stunned = false;
|
|
});
|
|
|
|
switch (direction)
|
|
{
|
|
case 2:
|
|
boyfriend.playAnim('singUPmiss', true);
|
|
case 3:
|
|
boyfriend.playAnim('singRIGHTmiss', true);
|
|
case 1:
|
|
boyfriend.playAnim('singDOWNmiss', true);
|
|
case 0:
|
|
boyfriend.playAnim('singLEFTmiss', true);
|
|
}
|
|
}
|
|
}
|
|
|
|
function badNoteCheck()
|
|
{
|
|
// just double pasting this shit cuz fuk u
|
|
// REDO THIS SYSTEM!
|
|
var upP = controls.UP_P;
|
|
var rightP = controls.RIGHT_P;
|
|
var downP = controls.DOWN_P;
|
|
var leftP = controls.LEFT_P;
|
|
|
|
var gamepad = FlxG.gamepads.lastActive;
|
|
if (gamepad != null)
|
|
{
|
|
if (gamepad.anyJustPressed(["DPAD_LEFT", "LEFT_STICK_DIGITAL_LEFT", X]))
|
|
{
|
|
leftP = true;
|
|
}
|
|
|
|
if (gamepad.anyJustPressed(["DPAD_RIGHT", "LEFT_STICK_DIGITAL_RIGHT", B]))
|
|
{
|
|
rightP = true;
|
|
}
|
|
|
|
if (gamepad.anyJustPressed(['DPAD_UP', "LEFT_STICK_DIGITAL_UP", Y]))
|
|
{
|
|
upP = true;
|
|
}
|
|
|
|
if (gamepad.anyJustPressed(["DPAD_DOWN", "LEFT_STICK_DIGITAL_DOWN", A]))
|
|
{
|
|
downP = true;
|
|
}
|
|
}
|
|
|
|
if (leftP)
|
|
noteMiss(0);
|
|
if (upP)
|
|
noteMiss(2);
|
|
if (rightP)
|
|
noteMiss(3);
|
|
if (downP)
|
|
noteMiss(1);
|
|
}
|
|
|
|
function noteCheck(keyP:Bool, note:Note):Void
|
|
{
|
|
trace(note.noteData + ' note check here ' + keyP);
|
|
if (keyP)
|
|
goodNoteHit(note);
|
|
else
|
|
badNoteCheck();
|
|
}
|
|
|
|
function goodNoteHit(note:Note):Void
|
|
{
|
|
if (!note.wasGoodHit)
|
|
{
|
|
if (!note.isSustainNote)
|
|
{
|
|
popUpScore(note.strumTime);
|
|
combo += 1;
|
|
}
|
|
|
|
if (note.noteData >= 0)
|
|
health += 0.03;
|
|
else
|
|
health += 0.007;
|
|
|
|
switch (note.noteData)
|
|
{
|
|
case 2:
|
|
boyfriend.playAnim('singUP');
|
|
case 3:
|
|
boyfriend.playAnim('singRIGHT');
|
|
case 1:
|
|
boyfriend.playAnim('singDOWN');
|
|
case 0:
|
|
boyfriend.playAnim('singLEFT');
|
|
}
|
|
|
|
playerStrums.forEach(function(spr:FlxSprite)
|
|
{
|
|
if (Math.abs(note.noteData) == spr.ID)
|
|
{
|
|
spr.animation.play('confirm', true);
|
|
}
|
|
});
|
|
|
|
note.wasGoodHit = true;
|
|
vocals.volume = 1;
|
|
|
|
note.kill();
|
|
notes.remove(note, true);
|
|
note.destroy();
|
|
}
|
|
}
|
|
|
|
override function stepHit()
|
|
{
|
|
if (SONG.needsVoices)
|
|
{
|
|
if (vocals.time > Conductor.songPosition + Conductor.stepCrochet
|
|
|| vocals.time < Conductor.songPosition - Conductor.stepCrochet)
|
|
{
|
|
vocals.pause();
|
|
vocals.time = Conductor.songPosition;
|
|
vocals.play();
|
|
}
|
|
}
|
|
|
|
if (dad.curCharacter == 'spooky' && totalSteps % 4 == 2)
|
|
{
|
|
// dad.dance();
|
|
}
|
|
|
|
super.stepHit();
|
|
}
|
|
|
|
override function beatHit()
|
|
{
|
|
super.beatHit();
|
|
|
|
if (generatedMusic)
|
|
{
|
|
notes.sort(FlxSort.byY, FlxSort.DESCENDING);
|
|
}
|
|
|
|
if (SONG.notes[Math.floor(curStep / 16)] != null)
|
|
{
|
|
if (SONG.notes[Math.floor(curStep / 16)].changeBPM)
|
|
{
|
|
Conductor.changeBPM(SONG.notes[Math.floor(curStep / 16)].bpm);
|
|
FlxG.log.add('CHANGED BPM!');
|
|
}
|
|
else
|
|
Conductor.changeBPM(SONG.bpm);
|
|
|
|
// Dad doesnt interupt his own notes
|
|
if (SONG.notes[Math.floor(curStep / 16)].mustHitSection)
|
|
dad.dance();
|
|
}
|
|
// FlxG.log.add('change bpm' + SONG.notes[Std.int(curStep / 16)].changeBPM);
|
|
|
|
if (camZooming && FlxG.camera.zoom < 1.35 && totalBeats % 4 == 0)
|
|
FlxG.camera.zoom += 0.025;
|
|
|
|
healthHeads.setGraphicSize(Std.int(healthHeads.width + 20));
|
|
|
|
if (totalBeats % gfSpeed == 0)
|
|
{
|
|
gf.dance();
|
|
}
|
|
|
|
if (!boyfriend.animation.curAnim.name.startsWith("sing"))
|
|
boyfriend.playAnim('idle');
|
|
|
|
if (totalBeats % 8 == 6)
|
|
{
|
|
boyfriend.playAnim('hey', true);
|
|
|
|
if (SONG.song == 'Tutorial' && dad.curCharacter == 'gf')
|
|
{
|
|
dad.playAnim('cheer', true);
|
|
}
|
|
}
|
|
}
|
|
}
|