diff --git a/assets/data/characters/bf-dead.xml b/assets/data/characters/bf-dead.xml new file mode 100644 index 00000000..c7ddf764 --- /dev/null +++ b/assets/data/characters/bf-dead.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assets/data/scripts/pixel.hx b/assets/data/scripts/pixel.hx index 736fb8c9..3d4addf2 100644 --- a/assets/data/scripts/pixel.hx +++ b/assets/data/scripts/pixel.hx @@ -4,6 +4,7 @@ import funkin.scripting.events.NoteHitEvent; public var pixelNotesForBF = true; public var pixelNotesForDad = true; public var enablePixelUI = true; +public var enablePixelGameOver = true; public var enableCameraHacks = true; public var enablePauseMenu = true; public var isSpooky = false; @@ -91,6 +92,11 @@ function postCreate() { makeCameraPixely(camGame); defaultCamZoom /= daPixelZoom; } + if (enablePixelGameOver) { + gameOverSong = "pixel/gameOver"; + lossSFX = "pixel/gameOverSFX"; + retrySFX = "pixel/gameOverEnd"; + } } function onStartCountdown() { diff --git a/assets/images/characters/bf-dead.png b/assets/images/characters/bf-dead.png new file mode 100644 index 00000000..ab244180 Binary files /dev/null and b/assets/images/characters/bf-dead.png differ diff --git a/assets/images/characters/bf-dead.xml b/assets/images/characters/bf-dead.xml new file mode 100644 index 00000000..b42e3cd2 --- /dev/null +++ b/assets/images/characters/bf-dead.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/music/gameOverEnd.mp3 b/assets/music/gameOverEnd.mp3 deleted file mode 100644 index 684181be..00000000 Binary files a/assets/music/gameOverEnd.mp3 and /dev/null differ diff --git a/assets/music/gameOverEnd.ogg b/assets/music/gameOverEnd.ogg deleted file mode 100644 index f1010742..00000000 Binary files a/assets/music/gameOverEnd.ogg and /dev/null differ diff --git a/assets/music/pixel/gameOver-pixel.mp3 b/assets/music/pixel/gameOver.mp3 similarity index 100% rename from assets/music/pixel/gameOver-pixel.mp3 rename to assets/music/pixel/gameOver.mp3 diff --git a/assets/music/pixel/gameOver-pixel.ogg b/assets/music/pixel/gameOver.ogg similarity index 100% rename from assets/music/pixel/gameOver-pixel.ogg rename to assets/music/pixel/gameOver.ogg diff --git a/assets/sounds/gameOverEnd.mp3 b/assets/sounds/gameOverEnd.mp3 new file mode 100644 index 00000000..cd77340c Binary files /dev/null and b/assets/sounds/gameOverEnd.mp3 differ diff --git a/assets/sounds/gameOverEnd.ogg b/assets/sounds/gameOverEnd.ogg new file mode 100644 index 00000000..b1c2c219 Binary files /dev/null and b/assets/sounds/gameOverEnd.ogg differ diff --git a/assets/sounds/fnf_loss_sfx.mp3 b/assets/sounds/gameOverSFX.mp3 similarity index 100% rename from assets/sounds/fnf_loss_sfx.mp3 rename to assets/sounds/gameOverSFX.mp3 diff --git a/assets/sounds/fnf_loss_sfx.ogg b/assets/sounds/gameOverSFX.ogg similarity index 100% rename from assets/sounds/fnf_loss_sfx.ogg rename to assets/sounds/gameOverSFX.ogg diff --git a/assets/music/pixel/gameOverEnd-pixel.mp3 b/assets/sounds/pixel/gameOverEnd.mp3 similarity index 100% rename from assets/music/pixel/gameOverEnd-pixel.mp3 rename to assets/sounds/pixel/gameOverEnd.mp3 diff --git a/assets/music/pixel/gameOverEnd-pixel.ogg b/assets/sounds/pixel/gameOverEnd.ogg similarity index 100% rename from assets/music/pixel/gameOverEnd-pixel.ogg rename to assets/sounds/pixel/gameOverEnd.ogg diff --git a/assets/sounds/fnf_loss_sfx-pixel.mp3 b/assets/sounds/pixel/gameOverSFX.mp3 similarity index 100% rename from assets/sounds/fnf_loss_sfx-pixel.mp3 rename to assets/sounds/pixel/gameOverSFX.mp3 diff --git a/assets/sounds/fnf_loss_sfx-pixel.ogg b/assets/sounds/pixel/gameOverSFX.ogg similarity index 100% rename from assets/sounds/fnf_loss_sfx-pixel.ogg rename to assets/sounds/pixel/gameOverSFX.ogg diff --git a/buildnumber.txt b/buildnumber.txt index aede7734..6f5d72ea 100644 --- a/buildnumber.txt +++ b/buildnumber.txt @@ -1 +1 @@ -1384 \ No newline at end of file +1391 \ No newline at end of file diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx index 0b5aab40..a04e7a03 100644 --- a/source/funkin/game/Character.hx +++ b/source/funkin/game/Character.hx @@ -47,6 +47,7 @@ class Character extends FlxSprite implements IBeatReceiver implements IOffsetCom public var playerOffsets:Bool = false; public var icon:String = null; + public var gameOverCharacter:String = "bf-dead"; public var cameraOffset:FlxPoint = new FlxPoint(0, 0); public var globalOffset:FlxPoint = new FlxPoint(0, 0); @@ -111,6 +112,7 @@ class Character extends FlxSprite implements IBeatReceiver implements IOffsetCom if (xml.has.isGF) isGF = (xml.att.isGF == "true"); if (xml.has.x) globalOffset.x = Std.parseFloat(xml.att.x); if (xml.has.y) globalOffset.y = Std.parseFloat(xml.att.y); + if (xml.has.gameOverChar) gameOverCharacter = xml.att.gameOverChar; if (xml.has.camx) cameraOffset.x = Std.parseFloat(xml.att.camx); if (xml.has.camy) cameraOffset.y = Std.parseFloat(xml.att.camy); if (xml.has.holdTime) holdTime = CoolUtil.getDefault(Std.parseFloat(xml.att.holdTime), 4); @@ -142,56 +144,6 @@ class Character extends FlxSprite implements IBeatReceiver implements IOffsetCom /** NON CONVERTED CHARACTERS - DO NOT REMOVE **/ - // case 'gf-pixel': - // tex = Paths.getSparrowAtlas('weeb/gfPixel'); - // frames = tex; - // animation.addByIndices('singUP', 'GF IDLE', [2], "", 24, false); - // animation.addByIndices('danceLeft', 'GF IDLE', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false); - // animation.addByIndices('danceRight', 'GF IDLE', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false); - - // addOffset('danceLeft', 0); - // addOffset('danceRight', 0); - - // playAnim('danceRight'); - - // setGraphicSize(Std.int(width * PlayState.daPixelZoom)); - // updateHitbox(); - // antialiasing = false; - // flipX = true; - - // case 'bf-pixel': - // frames = Paths.getSparrowAtlas('weeb/bfPixel'); - // animation.addByPrefix('idle', 'BF IDLE', 24, false); - // animation.addByPrefix('singUP', 'BF UP NOTE', 24, false); - // animation.addByPrefix('singLEFT', 'BF LEFT NOTE', 24, false); - // animation.addByPrefix('singRIGHT', 'BF RIGHT NOTE', 24, false); - // animation.addByPrefix('singDOWN', 'BF DOWN NOTE', 24, false); - // animation.addByPrefix('singUPmiss', 'BF UP MISS', 24, false); - // animation.addByPrefix('singLEFTmiss', 'BF LEFT MISS', 24, false); - // animation.addByPrefix('singRIGHTmiss', 'BF RIGHT MISS', 24, false); - // animation.addByPrefix('singDOWNmiss', 'BF DOWN MISS', 24, false); - - // addOffset('idle'); - // addOffset("singUP"); - // addOffset("singRIGHT"); - // addOffset("singLEFT"); - // addOffset("singDOWN"); - // addOffset("singUPmiss"); - // addOffset("singRIGHTmiss"); - // addOffset("singLEFTmiss"); - // addOffset("singDOWNmiss"); - - // setGraphicSize(Std.int(width * 6)); - // updateHitbox(); - - // playAnim('idle'); - - // width -= 100; - // height -= 100; - - // antialiasing = false; - - // flipX = true; // case 'bf-pixel-dead': // frames = Paths.getSparrowAtlas('weeb/bfPixelsDEAD'); // animation.addByPrefix('singUP', "BF Dies pixel", 24, false); @@ -210,67 +162,6 @@ class Character extends FlxSprite implements IBeatReceiver implements IOffsetCom // antialiasing = false; // flipX = true; - // case 'senpai': - // frames = Paths.getSparrowAtlas('weeb/senpai'); - // animation.addByPrefix('idle', 'Senpai Idle', 24, false); - // animation.addByPrefix('singUP', 'SENPAI UP NOTE', 24, false); - // animation.addByPrefix('singLEFT', 'SENPAI LEFT NOTE', 24, false); - // animation.addByPrefix('singRIGHT', 'SENPAI RIGHT NOTE', 24, false); - // animation.addByPrefix('singDOWN', 'SENPAI DOWN NOTE', 24, false); - - // addOffset('idle'); - // addOffset("singUP", 5, 37); - // addOffset("singRIGHT"); - // addOffset("singLEFT", 40); - // addOffset("singDOWN", 14); - - // playAnim('idle'); - - // setGraphicSize(Std.int(width * 6)); - // updateHitbox(); - - // antialiasing = false; - // case 'senpai-angry': - // frames = Paths.getSparrowAtlas('weeb/senpai'); - // animation.addByPrefix('idle', 'Angry Senpai Idle', 24, false); - // animation.addByPrefix('singUP', 'Angry Senpai UP NOTE', 24, false); - // animation.addByPrefix('singLEFT', 'Angry Senpai LEFT NOTE', 24, false); - // animation.addByPrefix('singRIGHT', 'Angry Senpai RIGHT NOTE', 24, false); - // animation.addByPrefix('singDOWN', 'Angry Senpai DOWN NOTE', 24, false); - - // addOffset('idle'); - // addOffset("singUP", 5, 37); - // addOffset("singRIGHT"); - // addOffset("singLEFT", 40); - // addOffset("singDOWN", 14); - // playAnim('idle'); - - // setGraphicSize(Std.int(width * 6)); - // updateHitbox(); - - // antialiasing = false; - - // case 'spirit': - // frames = Paths.getPackerAtlas('weeb/spirit'); - // animation.addByPrefix('idle', "idle spirit_", 24, false); - // animation.addByPrefix('singUP', "up_", 24, false); - // animation.addByPrefix('singRIGHT', "right_", 24, false); - // animation.addByPrefix('singLEFT', "left_", 24, false); - // animation.addByPrefix('singDOWN', "spirit down_", 24, false); - - // addOffset('idle', -220, -280); - // addOffset('singUP', -220, -240); - // addOffset("singRIGHT", -220, -280); - // addOffset("singLEFT", -200, -280); - // addOffset("singDOWN", 170, 110); - - // setGraphicSize(Std.int(width * 6)); - // updateHitbox(); - - // playAnim('idle'); - - // antialiasing = false; - isDanceLeftDanceRight = (animation.getByName("danceLeft") != null && animation.getByName("danceRight") != null); diff --git a/source/funkin/game/GameOverSubstate.hx b/source/funkin/game/GameOverSubstate.hx index c467c04b..01641dce 100644 --- a/source/funkin/game/GameOverSubstate.hx +++ b/source/funkin/game/GameOverSubstate.hx @@ -14,24 +14,26 @@ import funkin.system.Conductor; class GameOverSubstate extends MusicBeatSubstate { - var bf:Character; - public var character:String; + var character:Character; + public var characterName:String; public var gameOverSong:String; + public var lossSFXName:String; + public var retrySFX:String; var camFollow:FlxObject; - var stageSuffix:String = ""; - var x:Float = 0; var y:Float = 0; public var lossSFX:FlxSound; - public function new(x:Float, y:Float, character:String = "bf", gameOverSong:String = "gameOver") { + public function new(x:Float, y:Float, character:String = "bf-dead", gameOverSong:String = "gameOver", lossSFX:String = "gameOverSFX", retrySFX:String = "gameOverEnd") { super(); this.x = x; this.y = y; - this.character = character; + this.characterName = character; this.gameOverSong = gameOverSong; + this.lossSFXName = lossSFX; + this.retrySFX = retrySFX; } public override function create() @@ -40,18 +42,18 @@ class GameOverSubstate extends MusicBeatSubstate if (FlxG.sound.music != null) FlxG.sound.music.stop(); - bf = new Character(x, y, character, true); - add(bf); + character = new Character(x, y, characterName, true); + character.danceOnBeat = false; + character.playAnim('firstDeath'); + add(character); - camFollow = new FlxObject(bf.getGraphicMidpoint().x, bf.getGraphicMidpoint().y, 1, 1); + var camPos = character.getCameraPosition(); + camFollow = new FlxObject(camPos.x, camPos.y, 1, 1); add(camFollow); FlxG.camera.target = camFollow; - lossSFX = FlxG.sound.play(Paths.sound('fnf_loss_sfx' + stageSuffix)); + lossSFX = FlxG.sound.play(Paths.sound(lossSFXName)); Conductor.changeBPM(100); - - bf.danceOnBeat = false; - bf.playAnim('firstDeath'); } override function update(elapsed:Float) @@ -67,6 +69,7 @@ class GameOverSubstate extends MusicBeatSubstate { if (FlxG.sound.music != null) FlxG.sound.music.stop(); + FlxG.sound.music = null; if (PlayState.isStoryMode) FlxG.switchState(new StoryMenuState()); @@ -74,7 +77,7 @@ class GameOverSubstate extends MusicBeatSubstate FlxG.switchState(new FreeplayState()); } - if (!lossSFX.playing && (FlxG.sound.music == null || !FlxG.sound.music.playing)) + if (!isEnding && ((!lossSFX.playing) || (character.animation.curAnim != null && character.animation.curAnim.name == "firstDeath" && character.animation.curAnim.finished)) && (FlxG.sound.music == null || !FlxG.sound.music.playing)) CoolUtil.playMusic(Paths.music(gameOverSong), 100); } @@ -82,7 +85,7 @@ class GameOverSubstate extends MusicBeatSubstate { super.beatHit(curBeat); if (!lossSFX.playing) - bf.playAnim("deathLoop", DANCE); + character.playAnim("deathLoop", true, DANCE); } var isEnding:Bool = false; @@ -92,12 +95,22 @@ class GameOverSubstate extends MusicBeatSubstate if (!isEnding) { isEnding = true; - bf.playAnim('deathConfirm', true); + character.playAnim('deathConfirm', true); FlxG.sound.music.stop(); - FlxG.sound.play(Paths.music('gameOverEnd' + stageSuffix)); - new FlxTimer().start(0.7, function(tmr:FlxTimer) + var sound = FlxG.sound.play(Paths.sound(retrySFX)); + + var secsLength:Float = sound.length / 1000; + var waitTime = 0.7; + var fadeOutTime = secsLength - 0.7; + + if (fadeOutTime < 0.5) { + fadeOutTime = secsLength; + waitTime = 0; + } + + new FlxTimer().start(waitTime, function(tmr:FlxTimer) { - FlxG.camera.fade(FlxColor.BLACK, 2, false, function() + FlxG.camera.fade(FlxColor.BLACK, fadeOutTime, false, function() { FlxTransitionableState.skipNextTransOut = true; FlxG.switchState(new PlayState()); diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 6184a2b6..69f44ce6 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -80,7 +80,12 @@ class PlayState extends MusicBeatState public var scripts:ScriptPack; public var halloweenLevel:Bool = false; + public var gameOverSong:String = "gameOver"; + public var lossSFX:String = "fnf_loss_sfx"; + public var retrySFX:String = "gameOverEnd"; + public var stage:Stage; + public var canDie:Bool = true; public var scrollSpeed:Float = 0; public var downscroll(get, set):Bool; @@ -782,6 +787,8 @@ class PlayState extends MusicBeatState super.closeSubState(); } + var __wereVocalsPlaying:Bool = false; + var __wasAutoPause:Bool = false; override public function onFocus():Void { scripts.call("onFocus"); @@ -798,6 +805,8 @@ class PlayState extends MusicBeatState } } #end + if (__wasAutoPause && __wereVocalsPlaying) + vocals.play(); super.onFocus(); } @@ -811,6 +820,11 @@ class PlayState extends MusicBeatState DiscordClient.changePresence(detailsPausedText, SONG.song + " (" + difficultyText + ")", iconRPC); } #end + if (__wasAutoPause = FlxG.autoPause) { + __wereVocalsPlaying = vocals.playing; + vocals.pause(); + } + super.onFocusLost(); } @@ -1003,31 +1017,8 @@ class PlayState extends MusicBeatState trace("User is cheating!"); } - if (health <= 0) - { - boyfriend.stunned = true; - - persistentUpdate = false; - persistentDraw = false; - paused = true; - - vocals.stop(); - FlxG.sound.music.stop(); - - openSubState(new GameOverSubstate(boyfriend.x, boyfriend.y)); - - // FlxG.switchState(new GameOverState(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y)); - - #if desktop - // Game Over doesn't get his own variable because it's only used here - DiscordClient.changePresence("Game Over - " + detailsText, SONG.song + " (" + difficultyText + ")", iconRPC); - #end - } - - // while(unspawnNotes[0] != null && unspawnNotes[0].strumTime - Conductor.songPosition < 1500) - // notes.add(unspawnNotes.shift()); - - + if (health <= 0 && canDie) + gameOver(); if (generatedMusic) { @@ -1091,6 +1082,30 @@ class PlayState extends MusicBeatState scripts.call("postUpdate", [elapsed]); } + function gameOver(?character:String, ?gameOverSong:String, ?lossSFX:String, ?retrySFX:String) { + character = character.getDefault((boyfriend != null) ? boyfriend.gameOverCharacter : "bf-dead"); + gameOverSong.getDefault(this.gameOverSong); + lossSFX.getDefault(this.lossSFX); + retrySFX.getDefault(this.retrySFX); + + boyfriend.stunned = true; + + persistentUpdate = false; + persistentDraw = false; + paused = true; + + vocals.stop(); + if (FlxG.sound.music != null) + FlxG.sound.music.stop(); + + openSubState(new GameOverSubstate(boyfriend.x, boyfriend.y, character, gameOverSong, lossSFX, retrySFX)); + + #if desktop + // Game Over doesn't get his own variable because it's only used here + DiscordClient.changePresence("Game Over - " + detailsText, SONG.song + " (" + difficultyText + ")", iconRPC); + #end + } + function endSong():Void { scripts.call("onSongEnd");