305 lines
9.8 KiB
Plaintext
Executable File
305 lines
9.8 KiB
Plaintext
Executable File
import flixel.FlxG;
|
|
import flixel.FlxSprite;
|
|
import flixel.math.FlxBasePoint;
|
|
import flixel.tweens.FlxTween;
|
|
import flixel.tweens.FlxEase;
|
|
import flixel.util.FlxTimer;
|
|
import funkin.Conductor;
|
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
|
import funkin.graphics.FunkinSprite;
|
|
import funkin.modding.base.ScriptedFlxAtlasSprite;
|
|
import funkin.Paths;
|
|
import funkin.data.song.SongRegistry;
|
|
import funkin.play.GameOverSubState;
|
|
import funkin.play.PlayState;
|
|
import funkin.play.song.Song;
|
|
import funkin.play.stage.StageProp;
|
|
import funkin.save.Save;
|
|
import funkin.audio.FunkinSound;
|
|
import funkin.play.cutscene.VideoCutscene;
|
|
import funkin.play.cutscene.CutsceneType;
|
|
|
|
import funkin.play.PlayStatePlaylist;
|
|
|
|
class DarnellSong extends Song {
|
|
var hasPlayedCutscene:Bool;
|
|
var hasPlayedInGameCutscene:Bool;
|
|
var cutsceneMusic:FunkinSound;
|
|
var cutsceneConductor:Conductor;
|
|
var bgSprite:FunkinSprite;
|
|
|
|
public function new() {
|
|
super('darnell');
|
|
|
|
hasPlayedCutscene = false;
|
|
hasPlayedInGameCutscene = false;
|
|
}
|
|
|
|
public function listDifficulties(variationId:String, variationIds:Array<String>, showLocked:Bool):Array<String> {
|
|
if (showLocked || Save.instance.hasBeatenLevel('weekend1')) {
|
|
return super.listDifficulties(variationId, variationIds);
|
|
}
|
|
|
|
// Hide all difficulties if the player has not beaten the week.
|
|
return [];
|
|
}
|
|
|
|
public override function onCountdownStart(event:CountdownScriptEvent):Void {
|
|
super.onCountdownStart(event);
|
|
|
|
if (!PlayStatePlaylist.isStoryMode){
|
|
hasPlayedCutscene = true;
|
|
hasPlayedInGameCutscene = true;
|
|
}
|
|
|
|
if(hasPlayedCutscene && !hasPlayedInGameCutscene){
|
|
trace('Pausing countdown to play in game cutscene');
|
|
|
|
hasPlayedInGameCutscene = true;
|
|
|
|
event.cancel(); // CANCEL THE COUNTDOWN!
|
|
|
|
PlayState.instance.camHUD.visible = false;
|
|
introCutscene();
|
|
}
|
|
|
|
if (!hasPlayedCutscene) {
|
|
trace('Pausing countdown to play a video cutscene (`darnell`)');
|
|
|
|
hasPlayedCutscene = true;
|
|
|
|
event.cancel(); // CANCEL THE COUNTDOWN!
|
|
|
|
PlayState.instance.tweenCameraZoom(1.3, 0, true);
|
|
|
|
// trace('Adding black background behind cutscene over UI');
|
|
bgSprite = new FunkinSprite(0, 0);
|
|
bgSprite.makeSolidColor(2000, 2500, 0xFF000000);
|
|
bgSprite.cameras = [PlayState.instance.camCutscene]; // Show over the HUD but below the video.
|
|
// this
|
|
bgSprite.zIndex = -10000;
|
|
PlayState.instance.add(bgSprite);
|
|
PlayState.instance.refresh();
|
|
|
|
startVideo();
|
|
|
|
}
|
|
}
|
|
|
|
function introCutscene(){
|
|
var picoPos:Array<Float> = [PlayState.instance.currentStage.getBoyfriend().cameraFocusPoint.x, PlayState.instance.currentStage.getBoyfriend().cameraFocusPoint.y];
|
|
var nenePos:Array<Float> = [PlayState.instance.currentStage.getGirlfriend().cameraFocusPoint.x, PlayState.instance.currentStage.getGirlfriend().cameraFocusPoint.y];
|
|
var darnellPos:Array<Float> = [PlayState.instance.currentStage.getDad().cameraFocusPoint.x, PlayState.instance.currentStage.getDad().cameraFocusPoint.y];
|
|
|
|
var cutsceneDelay:Float = 2;
|
|
|
|
cutsceneMusic = FunkinSound.load(Paths.music("darnellCanCutscene/darnellCanCutscene", "weekend1"), true);
|
|
cutsceneMusic.volume = 1;
|
|
|
|
cutsceneConductor = new Conductor();
|
|
|
|
var songMusicData:Null<SongMusicData> = SongRegistry.instance.parseMusicData('darnellCanCutscene');
|
|
if (songMusicData != null) {
|
|
cutsceneConductor.mapTimeChanges(songMusicData.timeChanges);
|
|
}
|
|
|
|
cutsceneConductor.onBeatHit.add(onCutsceneBeatHit);
|
|
|
|
var cutsceneCan:FunkinSprite = FunkinSprite.createSparrow(darnellPos[0], darnellPos[1], 'wked1_cutscene_1_can');
|
|
cutsceneCan.animation.addByPrefix('forward', "can kick quick0", 24, false);
|
|
cutsceneCan.animation.addByPrefix('up', "can kicked up0", 24, false);
|
|
PlayState.instance.currentStage.add(cutsceneCan);
|
|
cutsceneCan.visible = false;
|
|
|
|
var spraycanPile = PlayState.instance.currentStage.getNamedProp('spraycanPile');
|
|
cutsceneCan.x = spraycanPile.x + 30;
|
|
cutsceneCan.y = spraycanPile.y - 320;
|
|
cutsceneCan.zIndex = spraycanPile.zIndex - 1;
|
|
PlayState.instance.currentStage.refresh();
|
|
|
|
var newCan:ScriptedFlxAtlasSprite = ScriptedFlxAtlasSprite.init('SpraycanAtlasSprite', 0, 0);
|
|
var spraycanPile = PlayState.instance.currentStage.getNamedProp('spraycanPile');
|
|
newCan.x = spraycanPile.x - 430;
|
|
newCan.y = spraycanPile.y - 840;
|
|
newCan.zIndex = 300;
|
|
PlayState.instance.currentStage.add(newCan);
|
|
PlayState.instance.currentStage.refresh();
|
|
newCan.visible = false;
|
|
|
|
PlayState.instance.currentStage.getBoyfriend().playAnimation('intro1', true);
|
|
|
|
// camera sets up, pico does his animation showing him pissed
|
|
new FlxTimer().start(0.1, function(tmr)
|
|
{
|
|
PlayState.instance.tweenCameraToPosition(picoPos[0] + 250, picoPos[1], 0);
|
|
|
|
PlayState.instance.tweenCameraZoom(1.3, 0, true, FlxEase.quadInOut);
|
|
});
|
|
|
|
new FlxTimer().start(0.7, function(tmr){
|
|
cutsceneMusic.play(false);
|
|
FlxTween.tween(bgSprite, { alpha: 0}, 2, {startDelay: 0.3}, function(){bgSprite.visible = false;});
|
|
});
|
|
|
|
// move camera out to show everything
|
|
new FlxTimer().start(cutsceneDelay, function(tmr){
|
|
PlayState.instance.tweenCameraToPosition(darnellPos[0]+100, darnellPos[1], 2.5, FlxEase.quadInOut);
|
|
PlayState.instance.tweenCameraZoom(0.66, 2.5, true, FlxEase.quadInOut);
|
|
});
|
|
|
|
// darnell lights up a can
|
|
new FlxTimer().start(cutsceneDelay + 3, function(tmr)
|
|
{
|
|
PlayState.instance.currentStage.getDad().playAnimation('lightCan', true);
|
|
FunkinSound.playOnce(Paths.sound('Darnell_Lighter'), 1.0);
|
|
});
|
|
|
|
// pico cocks his gun, camera shifts to his side to show this
|
|
new FlxTimer().start(cutsceneDelay + 4, function(tmr)
|
|
{
|
|
PlayState.instance.currentStage.getBoyfriend().playAnimation('cock', true);
|
|
PlayState.instance.tweenCameraToPosition(darnellPos[0]+180, darnellPos[1], 0.4, FlxEase.backOut);
|
|
FunkinSound.playOnce(Paths.sound('Gun_Prep'), 1.0);
|
|
});
|
|
|
|
// darnell kicks the can up
|
|
new FlxTimer().start(cutsceneDelay + 4.4, function(tmr)
|
|
{
|
|
PlayState.instance.currentStage.getDad().playAnimation('kickCan', true);
|
|
FunkinSound.playOnce(Paths.sound('Kick_Can_UP'), 1.0);
|
|
cutsceneCan.animation.play('up');
|
|
cutsceneCan.visible = true;
|
|
});
|
|
|
|
// darnell knees the can forward
|
|
new FlxTimer().start(cutsceneDelay + 4.9, function(tmr)
|
|
{
|
|
PlayState.instance.currentStage.getDad().playAnimation('kneeCan', true);
|
|
FunkinSound.playOnce(Paths.sound('Kick_Can_FORWARD'), 1.0);
|
|
cutsceneCan.animation.play('forward');
|
|
});
|
|
|
|
// pico shoots the can, it explodes
|
|
new FlxTimer().start(cutsceneDelay + 5.1, function(tmr)
|
|
{
|
|
PlayState.instance.currentStage.getBoyfriend().playAnimation('intro2', true, true);
|
|
|
|
FunkinSound.playOnce(Paths.soundRandom('shot', 1, 4));
|
|
|
|
PlayState.instance.tweenCameraToPosition(darnellPos[0]+100, darnellPos[1], 1, FlxEase.quadInOut);
|
|
|
|
newCan.scriptCall('playCanShot');
|
|
newCan.visible = true;
|
|
cutsceneCan.visible = false;
|
|
new FlxTimer().start(1/24, function(tmr)
|
|
{
|
|
darkenStageProps();
|
|
});
|
|
});
|
|
|
|
// darnell laughs
|
|
new FlxTimer().start(cutsceneDelay + 5.9, function(tmr)
|
|
{
|
|
PlayState.instance.currentStage.getDad().playAnimation('laughCutscene', true);
|
|
FunkinSound.playOnce(Paths.sound('cutscene/darnell_laugh'), 0.6);
|
|
});
|
|
|
|
// nene spits and laughs
|
|
new FlxTimer().start(cutsceneDelay + 6.2, function(tmr)
|
|
{
|
|
PlayState.instance.currentStage.getGirlfriend().playAnimation('laughCutscene', true);
|
|
FunkinSound.playOnce(Paths.sound('cutscene/nene_laugh'), 0.6);
|
|
});
|
|
|
|
// camera returns to normal, cutscene flags set and countdown starts.
|
|
new FlxTimer().start(cutsceneDelay + 8, function(tmr)
|
|
{
|
|
PlayState.instance.tweenCameraZoom(0.77, 2, true, FlxEase.sineInOut);
|
|
PlayState.instance.tweenCameraToPosition(darnellPos[0]+180, darnellPos[1], 2, FlxEase.sineInOut);
|
|
PlayState.instance.isInCutscene = false;
|
|
PlayState.instance.startCountdown();
|
|
cutsceneMusic.stop(); // stop the music!!!!!!
|
|
});
|
|
}
|
|
|
|
function onCutsceneBeatHit() {
|
|
// Play idle if Darnell isn't busy.
|
|
if (PlayState.instance.currentStage.getDad().isAnimationFinished()
|
|
&& PlayState.instance.currentStage.getDad().getCurrentAnimation() != 'lightCan') {
|
|
PlayState.instance.currentStage.getDad().dance(true);
|
|
}
|
|
|
|
if (PlayState.instance.currentStage.getGirlfriend().isAnimationFinished()) {
|
|
PlayState.instance.currentStage.getGirlfriend().dance(true);
|
|
}
|
|
}
|
|
|
|
function darkenStageProps()
|
|
{
|
|
// Darken the background, then fade it back.
|
|
for (stageProp in PlayState.instance.currentStage.members)
|
|
{
|
|
// Determine if the stage prop is something that should be excluded from darkening.
|
|
if (Std.isOfType(stageProp, StageProp)) {
|
|
if (stageProp.name == "bf" || stageProp.name == "dad" || stageProp.name == "gf") // This refers to the player.
|
|
{
|
|
// Exclude.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Hacky way of selecting PicoPlayable.picoFade.
|
|
if (stageProp.zIndex == (PlayState.instance.currentStage.getBoyfriend().zIndex - 3)) {
|
|
// Exclude.
|
|
continue;
|
|
}
|
|
|
|
if(stageProp.zIndex > 299){
|
|
continue;
|
|
}
|
|
|
|
// If not excluded, darken.
|
|
stageProp.color = 0xFF111111;
|
|
new FlxTimer().start(1/24, (tmr) ->
|
|
{
|
|
stageProp.color = 0xFF222222;
|
|
FlxTween.color(stageProp, 1.4, 0xFF222222, 0xFFFFFFFF);
|
|
});
|
|
}
|
|
}
|
|
|
|
function startVideo() {
|
|
VideoCutscene.play(Paths.videos('darnellCutscene'));
|
|
}
|
|
|
|
/**
|
|
* Don't replay the cutscene between restarts.
|
|
*/
|
|
function onSongRetry(event:ScriptEvent)
|
|
{
|
|
super.onSongRetry(event);
|
|
|
|
hasPlayedCutscene = true;
|
|
hasPlayedInGameCutscene = true;
|
|
}
|
|
|
|
/**
|
|
* Replay the cutscene after leaving the song.
|
|
*/
|
|
function onCreate(event:ScriptEvent):Void
|
|
{
|
|
super.onCreate(event);
|
|
|
|
hasPlayedCutscene = false;
|
|
hasPlayedInGameCutscene = false;
|
|
}
|
|
|
|
function onUpdate(event:UpdateScriptEvent) {
|
|
super.onUpdate(event);
|
|
|
|
if (cutsceneConductor != null && cutsceneMusic != null) {
|
|
cutsceneConductor.update(cutsceneMusic.time);
|
|
}
|
|
}
|
|
}
|