2022-03-08 03:13:53 -05:00
|
|
|
package funkin;
|
2020-10-27 06:35:23 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
import funkin.modding.events.ScriptEventDispatcher;
|
|
|
|
import funkin.modding.events.ScriptEvent;
|
|
|
|
import funkin.play.character.BaseCharacter;
|
2020-10-27 06:35:23 -04:00
|
|
|
import flixel.FlxObject;
|
|
|
|
import flixel.FlxSubState;
|
|
|
|
import flixel.math.FlxPoint;
|
2021-09-24 11:51:15 -04:00
|
|
|
import flixel.system.FlxSound;
|
2020-10-28 03:03:32 -04:00
|
|
|
import flixel.util.FlxColor;
|
|
|
|
import flixel.util.FlxTimer;
|
2022-03-08 03:13:53 -05:00
|
|
|
import haxe.display.Display;
|
|
|
|
import funkin.ui.PreferencesMenu;
|
|
|
|
import funkin.play.PlayState;
|
2020-10-27 06:35:23 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
using StringTools;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A substate which renders over the PlayState when the player dies.
|
|
|
|
* Displays the player death animation, plays the music, and handles restarting the song.
|
|
|
|
*
|
|
|
|
* The newest implementation uses a substate, which prevents having to reload the song and stage each reset.
|
|
|
|
*/
|
2020-10-28 05:26:33 -04:00
|
|
|
class GameOverSubstate extends MusicBeatSubstate
|
2020-10-27 06:35:23 -04:00
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
/**
|
|
|
|
* The boyfriend character.
|
|
|
|
*/
|
|
|
|
var boyfriend:BaseCharacter;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The invisible object in the scene which the camera focuses on.
|
|
|
|
*/
|
|
|
|
var cameraFollowPoint:FlxObject;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The music playing in the background of the state.
|
|
|
|
*/
|
|
|
|
var gameOverMusic:FlxSound = new FlxSound();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether the player has confirmed and prepared to restart the level.
|
|
|
|
* This means the animation and transition have already started.
|
|
|
|
*/
|
|
|
|
var isEnding:Bool = false;
|
2020-11-01 04:55:02 -05:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
/**
|
|
|
|
* Music variant to use.
|
|
|
|
* TODO: De-hardcode this somehow.
|
|
|
|
*/
|
|
|
|
var musicVariant:String = "";
|
2021-09-24 11:51:15 -04:00
|
|
|
|
2022-03-11 01:30:01 -05:00
|
|
|
public function new()
|
2020-10-27 06:35:23 -04:00
|
|
|
{
|
|
|
|
super();
|
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
FlxG.sound.list.add(gameOverMusic);
|
|
|
|
gameOverMusic.stop();
|
2020-10-27 06:35:23 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
Conductor.songPosition = 0;
|
2020-10-27 06:35:23 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
playBlueBalledSFX();
|
2020-10-27 06:35:23 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
switch (PlayState.instance.currentStageId)
|
2021-09-22 15:33:30 -04:00
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
case 'school' | 'schoolEvil':
|
|
|
|
musicVariant = "-pixel";
|
|
|
|
default:
|
|
|
|
if (PlayState.instance.currentStage.getBoyfriend().characterId == 'pico')
|
|
|
|
{
|
|
|
|
musicVariant = "Pico";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
musicVariant = "";
|
|
|
|
}
|
2021-09-22 15:33:30 -04:00
|
|
|
}
|
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
// We have to remove boyfriend from the stage. Then we can add him back at the end.
|
|
|
|
boyfriend = PlayState.instance.currentStage.getBoyfriend(true);
|
|
|
|
boyfriend.isDead = true;
|
|
|
|
boyfriend.playAnimation('firstDeath');
|
|
|
|
add(boyfriend);
|
2021-03-18 14:15:54 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1);
|
|
|
|
add(cameraFollowPoint);
|
2021-04-09 11:38:09 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
// FlxG.camera.scroll.set();
|
|
|
|
FlxG.camera.target = null;
|
|
|
|
FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.01);
|
2020-10-27 06:35:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
override function update(elapsed:Float)
|
|
|
|
{
|
2021-04-19 13:11:30 -04:00
|
|
|
// makes the lerp non-dependant on the framerate
|
2021-05-06 08:08:51 -04:00
|
|
|
// FlxG.camera.followLerp = CoolUtil.camLerpShit(0.01);
|
2021-04-19 13:11:30 -04:00
|
|
|
|
2020-10-27 06:35:23 -04:00
|
|
|
super.update(elapsed);
|
|
|
|
|
2021-08-22 10:37:06 -04:00
|
|
|
if (FlxG.onMobile)
|
|
|
|
{
|
|
|
|
var touch = FlxG.touches.getFirst();
|
|
|
|
if (touch != null)
|
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
if (touch.overlaps(boyfriend))
|
|
|
|
confirmDeath();
|
2021-08-22 10:37:06 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-01 02:58:20 -05:00
|
|
|
if (controls.ACCEPT)
|
2020-10-28 03:03:32 -04:00
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
confirmDeath();
|
2020-10-28 03:03:32 -04:00
|
|
|
}
|
|
|
|
|
2020-11-01 02:58:20 -05:00
|
|
|
if (controls.BACK)
|
|
|
|
{
|
2021-04-09 16:37:54 -04:00
|
|
|
PlayState.deathCounter = 0;
|
|
|
|
PlayState.seenCutscene = false;
|
2021-09-24 11:51:15 -04:00
|
|
|
// FlxG.sound.music.stop();
|
|
|
|
gameOverMusic.stop();
|
2020-11-01 02:58:20 -05:00
|
|
|
|
|
|
|
if (PlayState.isStoryMode)
|
|
|
|
FlxG.switchState(new StoryMenuState());
|
|
|
|
else
|
|
|
|
FlxG.switchState(new FreeplayState());
|
|
|
|
}
|
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
// Start panning the camera to BF after 12 frames.
|
|
|
|
// TODO: Should this be de-hardcoded?
|
|
|
|
if (boyfriend.getCurrentAnimation().startsWith('firstDeath') && boyfriend.animation.curAnim.curFrame == 12)
|
2020-10-27 06:35:23 -04:00
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x;
|
|
|
|
cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y;
|
2020-10-27 06:35:23 -04:00
|
|
|
}
|
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
if (gameOverMusic.playing)
|
2020-10-27 06:35:23 -04:00
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
Conductor.songPosition = gameOverMusic.time;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (PlayState.storyWeek)
|
|
|
|
{
|
|
|
|
case 7:
|
|
|
|
if (boyfriend.getCurrentAnimation().startsWith('firstDeath') && boyfriend.isAnimationFinished() && !playingJeffQuote)
|
|
|
|
{
|
|
|
|
playingJeffQuote = true;
|
|
|
|
playJeffQuote();
|
2021-04-18 05:25:44 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
startDeathMusic(0.2);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
if (boyfriend.getCurrentAnimation().startsWith('firstDeath') && boyfriend.isAnimationFinished())
|
2021-03-18 14:15:54 -04:00
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
startDeathMusic();
|
|
|
|
}
|
|
|
|
}
|
2020-10-27 06:35:23 -04:00
|
|
|
}
|
2020-10-28 05:26:33 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
dispatchEvent(new UpdateScriptEvent(elapsed));
|
|
|
|
}
|
|
|
|
|
|
|
|
override function dispatchEvent(event:ScriptEvent)
|
|
|
|
{
|
|
|
|
super.dispatchEvent(event);
|
|
|
|
|
|
|
|
ScriptEventDispatcher.callEvent(boyfriend, event);
|
2020-10-28 05:26:33 -04:00
|
|
|
}
|
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
/**
|
|
|
|
* Starts the death music at the appropriate volume.
|
|
|
|
* @param startingVolume
|
|
|
|
*/
|
|
|
|
function startDeathMusic(?startingVolume:Float = 1):Void
|
2021-03-18 14:15:54 -04:00
|
|
|
{
|
2021-04-19 04:43:21 -04:00
|
|
|
if (!isEnding)
|
2021-09-24 11:51:15 -04:00
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
gameOverMusic.loadEmbedded(Paths.music('gameOver' + musicVariant));
|
|
|
|
gameOverMusic.volume = startingVolume;
|
|
|
|
gameOverMusic.play();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gameOverMusic.loadEmbedded(Paths.music('gameOverEnd' + musicVariant));
|
|
|
|
gameOverMusic.volume = startingVolume;
|
2021-09-24 11:51:15 -04:00
|
|
|
gameOverMusic.play();
|
|
|
|
}
|
2020-10-27 06:35:23 -04:00
|
|
|
}
|
2020-10-28 03:03:32 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
/**
|
|
|
|
* Play the sound effect that occurs when
|
|
|
|
* boyfriend's testicles get utterly annihilated.
|
|
|
|
*/
|
|
|
|
function playBlueBalledSFX()
|
|
|
|
{
|
|
|
|
FlxG.sound.play(Paths.sound('fnf_loss_sfx' + musicVariant));
|
|
|
|
}
|
|
|
|
|
|
|
|
var playingJeffQuote:Bool = false;
|
2020-10-28 03:03:32 -04:00
|
|
|
|
2022-03-21 00:19:05 -04:00
|
|
|
/**
|
|
|
|
* Week 7-specific hardcoded behavior, to play a custom death quote.
|
|
|
|
* TODO: Make this a module somehow.
|
|
|
|
*/
|
|
|
|
function playJeffQuote()
|
|
|
|
{
|
|
|
|
var randomCensor:Array<Int> = [];
|
|
|
|
|
|
|
|
if (PreferencesMenu.getPref('censor-naughty'))
|
|
|
|
randomCensor = [1, 3, 8, 13, 17, 21];
|
|
|
|
|
|
|
|
FlxG.sound.play(Paths.sound('jeffGameover/jeffGameover-' + FlxG.random.int(1, 25, randomCensor)), 1, false, null, true, function()
|
|
|
|
{
|
|
|
|
// Once the quote ends, fade in the game over music.
|
|
|
|
if (!isEnding && gameOverMusic != null)
|
|
|
|
{
|
|
|
|
gameOverMusic.fadeIn(4, 0.2, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do behavior which occurs when you confirm and move to restart the level.
|
|
|
|
*/
|
|
|
|
function confirmDeath():Void
|
2020-10-28 03:03:32 -04:00
|
|
|
{
|
|
|
|
if (!isEnding)
|
|
|
|
{
|
|
|
|
isEnding = true;
|
2022-03-21 00:19:05 -04:00
|
|
|
startDeathMusic(); // isEnding changes this function's behavior.
|
|
|
|
|
|
|
|
boyfriend.playAnimation('deathConfirm', true);
|
|
|
|
|
|
|
|
// After the animation finishes...
|
2020-10-28 03:03:32 -04:00
|
|
|
new FlxTimer().start(0.7, function(tmr:FlxTimer)
|
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
// ...fade out the graphics. Then after that happens...
|
2020-10-28 03:03:32 -04:00
|
|
|
FlxG.camera.fade(FlxColor.BLACK, 2, false, function()
|
|
|
|
{
|
2022-03-21 00:19:05 -04:00
|
|
|
// ...close the GameOverSubstate.
|
2021-09-24 11:51:15 -04:00
|
|
|
FlxG.camera.fade(FlxColor.BLACK, 1, true, null, true);
|
|
|
|
PlayState.needsReset = true;
|
2022-03-21 00:19:05 -04:00
|
|
|
|
|
|
|
// Readd Boyfriend to the stage.
|
|
|
|
boyfriend.isDead = false;
|
|
|
|
remove(boyfriend);
|
|
|
|
PlayState.instance.currentStage.addCharacter(boyfriend, BF);
|
|
|
|
|
|
|
|
// Close the substate.
|
2021-09-24 11:51:15 -04:00
|
|
|
close();
|
2020-10-28 03:03:32 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2020-10-27 06:35:23 -04:00
|
|
|
}
|