Files
2025-06-22 12:00:12 -04:00

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);
}
}
}