mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-08-19 23:15:15 +00:00
Fix a dozen tiny issues with 2hot's audio and visuals (and some script crashes!).
This commit is contained in:
parent
5733386519
commit
d56c33cd17
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50
|
Subproject commit 82ee26e1f733d1b2f30015ae69925e6a39d6526b
|
|
@ -9,7 +9,7 @@ import openfl.utils.Assets as OpenFlAssets;
|
||||||
*/
|
*/
|
||||||
class Paths
|
class Paths
|
||||||
{
|
{
|
||||||
static var currentLevel:String;
|
static var currentLevel:Null<String> = null;
|
||||||
|
|
||||||
static public function setCurrentLevel(name:String)
|
static public function setCurrentLevel(name:String)
|
||||||
{
|
{
|
||||||
|
|
|
@ -276,16 +276,27 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
* Creates a new `FunkinSound` object and loads it as the current music track.
|
* Creates a new `FunkinSound` object and loads it as the current music track.
|
||||||
*
|
*
|
||||||
* @param key The key of the music you want to play. Music should be at `music/<key>/<key>.ogg`.
|
* @param key The key of the music you want to play. Music should be at `music/<key>/<key>.ogg`.
|
||||||
* @param startingVolume The volume you want the music to start at.
|
* @param params A set of additional optional parameters.
|
||||||
* @param overrideExisting Whether to override music if it is already playing.
|
|
||||||
* @param mapTimeChanges Whether to check for `SongMusicData` to update the Conductor with.
|
|
||||||
* Data should be at `music/<key>/<key>-metadata.json`.
|
* Data should be at `music/<key>/<key>-metadata.json`.
|
||||||
*/
|
*/
|
||||||
public static function playMusic(key:String, startingVolume:Float = 1.0, overrideExisting:Bool = false, mapTimeChanges:Bool = true):Void
|
public static function playMusic(key:String, params:FunkinSoundPlayMusicParams):Void
|
||||||
{
|
{
|
||||||
if (!overrideExisting && FlxG.sound.music?.playing) return;
|
if (!(params.overrideExisting ?? false) && FlxG.sound.music?.playing) return;
|
||||||
|
|
||||||
if (mapTimeChanges)
|
if (!(params.restartTrack ?? false) && FlxG.sound.music?.playing)
|
||||||
|
{
|
||||||
|
if (FlxG.sound.music != null && Std.isOfType(FlxG.sound.music, FunkinSound))
|
||||||
|
{
|
||||||
|
var existingSound:FunkinSound = cast FlxG.sound.music;
|
||||||
|
// Stop here if we would play a matching music track.
|
||||||
|
if (existingSound._label == Paths.music('$key/$key'))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params?.mapTimeChanges ?? true)
|
||||||
{
|
{
|
||||||
var songMusicData:Null<SongMusicData> = SongRegistry.instance.parseMusicData(key);
|
var songMusicData:Null<SongMusicData> = SongRegistry.instance.parseMusicData(key);
|
||||||
// Will fall back and return null if the metadata doesn't exist or can't be parsed.
|
// Will fall back and return null if the metadata doesn't exist or can't be parsed.
|
||||||
|
@ -299,7 +310,13 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), startingVolume);
|
if (FlxG.sound.music != null)
|
||||||
|
{
|
||||||
|
FlxG.sound.music.stop();
|
||||||
|
FlxG.sound.music.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
FlxG.sound.music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, true, false, true);
|
||||||
|
|
||||||
// Prevent repeat update() and onFocus() calls.
|
// Prevent repeat update() and onFocus() calls.
|
||||||
FlxG.sound.list.remove(FlxG.sound.music);
|
FlxG.sound.list.remove(FlxG.sound.music);
|
||||||
|
@ -333,10 +350,10 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
sound._label = embeddedSound;
|
sound._label = embeddedSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (autoPlay) sound.play();
|
||||||
sound.volume = volume;
|
sound.volume = volume;
|
||||||
sound.group = FlxG.sound.defaultSoundGroup;
|
sound.group = FlxG.sound.defaultSoundGroup;
|
||||||
sound.persist = true;
|
sound.persist = true;
|
||||||
if (autoPlay) sound.play();
|
|
||||||
|
|
||||||
// Call onLoad() because the sound already loaded
|
// Call onLoad() because the sound already loaded
|
||||||
if (onLoad != null && sound._sound != null) onLoad();
|
if (onLoad != null && sound._sound != null) onLoad();
|
||||||
|
@ -356,3 +373,33 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional parameters for `FunkinSound.playMusic()`
|
||||||
|
*/
|
||||||
|
typedef FunkinSoundPlayMusicParams =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The volume you want the music to start at.
|
||||||
|
* @default `1.0`
|
||||||
|
*/
|
||||||
|
var ?startingVolume:Float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to override music if a different track is already playing.
|
||||||
|
* @default `false`
|
||||||
|
*/
|
||||||
|
var ?overrideExisting:Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to override music if the same track is already playing.
|
||||||
|
* @default `false`
|
||||||
|
*/
|
||||||
|
var ?restartTrack:Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to check for `SongMusicData` to update the Conductor with.
|
||||||
|
* @default `true`
|
||||||
|
*/
|
||||||
|
var ?mapTimeChanges:Bool;
|
||||||
|
}
|
||||||
|
|
|
@ -151,14 +151,14 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
|
||||||
/**
|
/**
|
||||||
* Stop all the sounds in the group.
|
* Stop all the sounds in the group.
|
||||||
*/
|
*/
|
||||||
public function stop()
|
public function stop():Void
|
||||||
{
|
{
|
||||||
forEachAlive(function(sound:FunkinSound) {
|
forEachAlive(function(sound:FunkinSound) {
|
||||||
sound.stop();
|
sound.stop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function destroy()
|
public override function destroy():Void
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
super.destroy();
|
super.destroy();
|
||||||
|
@ -176,9 +176,14 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
|
||||||
|
|
||||||
function get_time():Float
|
function get_time():Float
|
||||||
{
|
{
|
||||||
if (getFirstAlive() != null) return getFirstAlive().time;
|
if (getFirstAlive() != null)
|
||||||
|
{
|
||||||
|
return getFirstAlive().time;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_time(time:Float):Float
|
function set_time(time:Float):Float
|
||||||
|
@ -193,16 +198,26 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
|
||||||
|
|
||||||
function get_playing():Bool
|
function get_playing():Bool
|
||||||
{
|
{
|
||||||
if (getFirstAlive() != null) return getFirstAlive().playing;
|
if (getFirstAlive() != null)
|
||||||
|
{
|
||||||
|
return getFirstAlive().playing;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_volume():Float
|
function get_volume():Float
|
||||||
{
|
{
|
||||||
if (getFirstAlive() != null) return getFirstAlive().volume;
|
if (getFirstAlive() != null)
|
||||||
|
{
|
||||||
|
return getFirstAlive().volume;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// in PlayState, adjust the code so that it only mutes the player1 vocal tracks?
|
// in PlayState, adjust the code so that it only mutes the player1 vocal tracks?
|
||||||
|
|
|
@ -8,7 +8,12 @@ import funkin.modding.IScriptedClass;
|
||||||
*/
|
*/
|
||||||
class ScriptEventDispatcher
|
class ScriptEventDispatcher
|
||||||
{
|
{
|
||||||
public static function callEvent(target:IScriptedClass, event:ScriptEvent):Void
|
/**
|
||||||
|
* Invoke the given event hook on the given scripted class.
|
||||||
|
* @param target The target class to call script hooks on.
|
||||||
|
* @param event The event, which determines the script hook to call and provides parameters for it.
|
||||||
|
*/
|
||||||
|
public static function callEvent(target:Null<IScriptedClass>, event:ScriptEvent):Void
|
||||||
{
|
{
|
||||||
if (target == null || event == null) return;
|
if (target == null || event == null) return;
|
||||||
|
|
||||||
|
|
|
@ -2,20 +2,18 @@ package funkin.play;
|
||||||
|
|
||||||
import flixel.FlxG;
|
import flixel.FlxG;
|
||||||
import flixel.FlxObject;
|
import flixel.FlxObject;
|
||||||
import flixel.FlxSprite;
|
import flixel.input.touch.FlxTouch;
|
||||||
import flixel.sound.FlxSound;
|
|
||||||
import funkin.audio.FunkinSound;
|
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
import funkin.modding.events.ScriptEventDispatcher;
|
||||||
import funkin.play.character.BaseCharacter;
|
import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.PlayState;
|
|
||||||
import funkin.util.MathUtil;
|
|
||||||
import funkin.ui.freeplay.FreeplayState;
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
import funkin.ui.MusicBeatSubState;
|
import funkin.ui.MusicBeatSubState;
|
||||||
import funkin.ui.story.StoryMenuState;
|
import funkin.ui.story.StoryMenuState;
|
||||||
|
import funkin.util.MathUtil;
|
||||||
import openfl.utils.Assets;
|
import openfl.utils.Assets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,13 +22,14 @@ import openfl.utils.Assets;
|
||||||
*
|
*
|
||||||
* The newest implementation uses a substate, which prevents having to reload the song and stage each reset.
|
* The newest implementation uses a substate, which prevents having to reload the song and stage each reset.
|
||||||
*/
|
*/
|
||||||
|
@:nullSafety
|
||||||
class GameOverSubState extends MusicBeatSubState
|
class GameOverSubState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The currently active GameOverSubState.
|
* The currently active GameOverSubState.
|
||||||
* There should be only one GameOverSubState in existance at a time, we can use a singleton.
|
* There should be only one GameOverSubState in existance at a time, we can use a singleton.
|
||||||
*/
|
*/
|
||||||
public static var instance:GameOverSubState = null;
|
public static var instance:Null<GameOverSubState> = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Which alternate animation on the character to use.
|
* Which alternate animation on the character to use.
|
||||||
|
@ -38,7 +37,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
* For example, playing a different animation when BF dies in Week 4
|
* For example, playing a different animation when BF dies in Week 4
|
||||||
* or Pico dies in Weekend 1.
|
* or Pico dies in Weekend 1.
|
||||||
*/
|
*/
|
||||||
public static var animationSuffix:String = "";
|
public static var animationSuffix:String = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Which alternate game over music to use.
|
* Which alternate game over music to use.
|
||||||
|
@ -46,17 +45,19 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
* For example, the bf-pixel script sets this to `-pixel`
|
* For example, the bf-pixel script sets this to `-pixel`
|
||||||
* and the pico-playable script sets this to `Pico`.
|
* and the pico-playable script sets this to `Pico`.
|
||||||
*/
|
*/
|
||||||
public static var musicSuffix:String = "";
|
public static var musicSuffix:String = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Which alternate "blue ball" sound effect to use.
|
* Which alternate "blue ball" sound effect to use.
|
||||||
*/
|
*/
|
||||||
public static var blueBallSuffix:String = "";
|
public static var blueBallSuffix:String = '';
|
||||||
|
|
||||||
|
static var blueballed:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The boyfriend character.
|
* The boyfriend character.
|
||||||
*/
|
*/
|
||||||
var boyfriend:BaseCharacter;
|
var boyfriend:Null<BaseCharacter> = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The invisible object in the scene which the camera focuses on.
|
* The invisible object in the scene which the camera focuses on.
|
||||||
|
@ -83,7 +84,8 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
|
|
||||||
var transparent:Bool;
|
var transparent:Bool;
|
||||||
|
|
||||||
final CAMERA_ZOOM_DURATION:Float = 0.5;
|
static final CAMERA_ZOOM_DURATION:Float = 0.5;
|
||||||
|
|
||||||
var targetCameraZoom:Float = 1.0;
|
var targetCameraZoom:Float = 1.0;
|
||||||
|
|
||||||
public function new(params:GameOverParams)
|
public function new(params:GameOverParams)
|
||||||
|
@ -92,24 +94,27 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
|
|
||||||
this.isChartingMode = params?.isChartingMode ?? false;
|
this.isChartingMode = params?.isChartingMode ?? false;
|
||||||
transparent = params.transparent;
|
transparent = params.transparent;
|
||||||
|
|
||||||
|
cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the game over configuration to the default.
|
* Reset the game over configuration to the default.
|
||||||
*/
|
*/
|
||||||
public static function reset()
|
public static function reset():Void
|
||||||
{
|
{
|
||||||
animationSuffix = "";
|
animationSuffix = '';
|
||||||
musicSuffix = "";
|
musicSuffix = '';
|
||||||
blueBallSuffix = "";
|
blueBallSuffix = '';
|
||||||
|
blueballed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function create()
|
public override function create():Void
|
||||||
{
|
{
|
||||||
if (instance != null)
|
if (instance != null)
|
||||||
{
|
{
|
||||||
// TODO: Do something in this case? IDK.
|
// TODO: Do something in this case? IDK.
|
||||||
trace('WARNING: GameOverSubState instance already exists. This should not happen.');
|
FlxG.log.warn('WARNING: GameOverSubState instance already exists. This should not happen.');
|
||||||
}
|
}
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
|
@ -120,7 +125,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
//
|
//
|
||||||
|
|
||||||
// Add a black background to the screen.
|
// Add a black background to the screen.
|
||||||
var bg = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
|
var bg:FunkinSprite = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
|
||||||
// We make this transparent so that we can see the stage underneath during debugging,
|
// We make this transparent so that we can see the stage underneath during debugging,
|
||||||
// but it's normally opaque.
|
// but it's normally opaque.
|
||||||
bg.alpha = transparent ? 0.25 : 1.0;
|
bg.alpha = transparent ? 0.25 : 1.0;
|
||||||
|
@ -135,18 +140,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
add(boyfriend);
|
add(boyfriend);
|
||||||
boyfriend.resetCharacter();
|
boyfriend.resetCharacter();
|
||||||
|
|
||||||
// Assign a camera follow point to the boyfriend's position.
|
setCameraTarget();
|
||||||
cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1);
|
|
||||||
cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x;
|
|
||||||
cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y;
|
|
||||||
var offsets:Array<Float> = boyfriend.getDeathCameraOffsets();
|
|
||||||
cameraFollowPoint.x += offsets[0];
|
|
||||||
cameraFollowPoint.y += offsets[1];
|
|
||||||
add(cameraFollowPoint);
|
|
||||||
|
|
||||||
FlxG.camera.target = null;
|
|
||||||
FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.01);
|
|
||||||
targetCameraZoom = PlayState?.instance?.currentStage?.camZoom * boyfriend.getDeathCameraZoom();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set up the audio
|
// Set up the audio
|
||||||
|
@ -156,6 +150,26 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
Conductor.instance.update(0);
|
Conductor.instance.update(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@:nullSafety(Off)
|
||||||
|
function setCameraTarget():Void
|
||||||
|
{
|
||||||
|
// Assign a camera follow point to the boyfriend's position.
|
||||||
|
cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x;
|
||||||
|
cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y;
|
||||||
|
var offsets:Array<Float> = boyfriend.getDeathCameraOffsets();
|
||||||
|
cameraFollowPoint.x += offsets[0];
|
||||||
|
cameraFollowPoint.y += offsets[1];
|
||||||
|
add(cameraFollowPoint);
|
||||||
|
|
||||||
|
FlxG.camera.target = null;
|
||||||
|
FlxG.camera.follow(cameraFollowPoint, LOCKON, Constants.DEFAULT_CAMERA_FOLLOW_RATE / 2);
|
||||||
|
targetCameraZoom = (PlayState?.instance?.currentStage?.camZoom ?? 1.0) * boyfriend.getDeathCameraZoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcibly reset the camera zoom level to that of the current stage.
|
||||||
|
* This prevents camera zoom events from adversely affecting the game over state.
|
||||||
|
*/
|
||||||
public function resetCameraZoom():Void
|
public function resetCameraZoom():Void
|
||||||
{
|
{
|
||||||
// Apply camera zoom level from stage data.
|
// Apply camera zoom level from stage data.
|
||||||
|
@ -164,21 +178,24 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
|
|
||||||
var hasStartedAnimation:Bool = false;
|
var hasStartedAnimation:Bool = false;
|
||||||
|
|
||||||
override function update(elapsed:Float)
|
override function update(elapsed:Float):Void
|
||||||
{
|
{
|
||||||
if (!hasStartedAnimation)
|
if (!hasStartedAnimation)
|
||||||
{
|
{
|
||||||
hasStartedAnimation = true;
|
hasStartedAnimation = true;
|
||||||
|
|
||||||
if (boyfriend.hasAnimation('fakeoutDeath') && FlxG.random.bool((1 / 4096) * 100))
|
if (boyfriend != null)
|
||||||
{
|
{
|
||||||
boyfriend.playAnimation('fakeoutDeath', true, false);
|
if (boyfriend.hasAnimation('fakeoutDeath') && FlxG.random.bool((1 / 4096) * 100))
|
||||||
}
|
{
|
||||||
else
|
boyfriend.playAnimation('fakeoutDeath', true, false);
|
||||||
{
|
}
|
||||||
boyfriend.playAnimation('firstDeath', true, false); // ignoreOther is set to FALSE since you WANT to be able to mash and confirm game over!
|
else
|
||||||
// Play the "blue balled" sound. May play a variant if one has been assigned.
|
{
|
||||||
playBlueBalledSFX();
|
boyfriend.playAnimation('firstDeath', true, false); // ignoreOther is set to FALSE since you WANT to be able to mash and confirm game over!
|
||||||
|
// Play the "blue balled" sound. May play a variant if one has been assigned.
|
||||||
|
playBlueBalledSFX();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,10 +209,10 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
// MOBILE ONLY: Restart the level when tapping Boyfriend.
|
// MOBILE ONLY: Restart the level when tapping Boyfriend.
|
||||||
if (FlxG.onMobile)
|
if (FlxG.onMobile)
|
||||||
{
|
{
|
||||||
var touch = FlxG.touches.getFirst();
|
var touch:FlxTouch = FlxG.touches.getFirst();
|
||||||
if (touch != null)
|
if (touch != null)
|
||||||
{
|
{
|
||||||
if (touch.overlaps(boyfriend))
|
if (boyfriend == null || touch.overlaps(boyfriend))
|
||||||
{
|
{
|
||||||
confirmDeath();
|
confirmDeath();
|
||||||
}
|
}
|
||||||
|
@ -215,7 +232,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
blueballed = false;
|
blueballed = false;
|
||||||
PlayState.instance.deathCounter = 0;
|
PlayState.instance.deathCounter = 0;
|
||||||
// PlayState.seenCutscene = false; // old thing...
|
// PlayState.seenCutscene = false; // old thing...
|
||||||
gameOverMusic.stop();
|
if (gameOverMusic != null) gameOverMusic.stop();
|
||||||
|
|
||||||
if (isChartingMode)
|
if (isChartingMode)
|
||||||
{
|
{
|
||||||
|
@ -239,14 +256,14 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
// This enables the stepHit and beatHit events.
|
// This enables the stepHit and beatHit events.
|
||||||
Conductor.instance.update(gameOverMusic.time);
|
Conductor.instance.update(gameOverMusic.time);
|
||||||
}
|
}
|
||||||
else
|
else if (boyfriend != null)
|
||||||
{
|
{
|
||||||
// Music hasn't started yet.
|
// Music hasn't started yet.
|
||||||
switch (PlayStatePlaylist.campaignId)
|
switch (PlayStatePlaylist.campaignId)
|
||||||
{
|
{
|
||||||
// TODO: Make the behavior for playing Jeff's voicelines generic or un-hardcoded.
|
// TODO: Make the behavior for playing Jeff's voicelines generic or un-hardcoded.
|
||||||
// This will simplify the class and make it easier for mods to add death quotes.
|
// This will simplify the class and make it easier for mods or future weeks to add death quotes.
|
||||||
case "week7":
|
case 'week7':
|
||||||
if (boyfriend.getCurrentAnimation().startsWith('firstDeath') && boyfriend.isAnimationFinished() && !playingJeffQuote)
|
if (boyfriend.getCurrentAnimation().startsWith('firstDeath') && boyfriend.isAnimationFinished() && !playingJeffQuote)
|
||||||
{
|
{
|
||||||
playingJeffQuote = true;
|
playingJeffQuote = true;
|
||||||
|
@ -279,7 +296,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
isEnding = true;
|
isEnding = true;
|
||||||
startDeathMusic(1.0, true); // isEnding changes this function's behavior.
|
startDeathMusic(1.0, true); // isEnding changes this function's behavior.
|
||||||
|
|
||||||
boyfriend.playAnimation('deathConfirm' + animationSuffix, true);
|
if (boyfriend != null) boyfriend.playAnimation('deathConfirm' + animationSuffix, true);
|
||||||
|
|
||||||
// After the animation finishes...
|
// After the animation finishes...
|
||||||
new FlxTimer().start(0.7, function(tmr:FlxTimer) {
|
new FlxTimer().start(0.7, function(tmr:FlxTimer) {
|
||||||
|
@ -290,9 +307,12 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
PlayState.instance.needsReset = true;
|
PlayState.instance.needsReset = true;
|
||||||
|
|
||||||
// Readd Boyfriend to the stage.
|
// Readd Boyfriend to the stage.
|
||||||
boyfriend.isDead = false;
|
if (boyfriend != null)
|
||||||
remove(boyfriend);
|
{
|
||||||
PlayState.instance.currentStage.addCharacter(boyfriend, BF);
|
boyfriend.isDead = false;
|
||||||
|
remove(boyfriend);
|
||||||
|
PlayState.instance.currentStage.addCharacter(boyfriend, BF);
|
||||||
|
}
|
||||||
|
|
||||||
// Snap reset the camera which may have changed because of the player character data.
|
// Snap reset the camera which may have changed because of the player character data.
|
||||||
resetCameraZoom();
|
resetCameraZoom();
|
||||||
|
@ -304,7 +324,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function dispatchEvent(event:ScriptEvent)
|
public override function dispatchEvent(event:ScriptEvent):Void
|
||||||
{
|
{
|
||||||
super.dispatchEvent(event);
|
super.dispatchEvent(event);
|
||||||
|
|
||||||
|
@ -317,11 +337,11 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
function resolveMusicPath(suffix:String, starting:Bool = false, ending:Bool = false):Null<String>
|
function resolveMusicPath(suffix:String, starting:Bool = false, ending:Bool = false):Null<String>
|
||||||
{
|
{
|
||||||
var basePath = 'gameplay/gameover/gameOver';
|
var basePath:String = 'gameplay/gameover/gameOver';
|
||||||
if (starting) basePath += 'Start';
|
if (ending) basePath += 'End';
|
||||||
else if (ending) basePath += 'End';
|
else if (starting) basePath += 'Start';
|
||||||
|
|
||||||
var musicPath = Paths.music(basePath + suffix);
|
var musicPath:String = Paths.music(basePath + suffix);
|
||||||
while (!Assets.exists(musicPath) && suffix.length > 0)
|
while (!Assets.exists(musicPath) && suffix.length > 0)
|
||||||
{
|
{
|
||||||
suffix = suffix.split('-').slice(0, -1).join('-');
|
suffix = suffix.split('-').slice(0, -1).join('-');
|
||||||
|
@ -334,23 +354,26 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the death music at the appropriate volume.
|
* Starts the death music at the appropriate volume.
|
||||||
* @param startingVolume
|
* @param startingVolume The initial volume for the music.
|
||||||
|
* @param force Whether or not to force the music to restart.
|
||||||
*/
|
*/
|
||||||
public function startDeathMusic(startingVolume:Float = 1, force:Bool = false):Void
|
public function startDeathMusic(startingVolume:Float = 1, force:Bool = false):Void
|
||||||
{
|
{
|
||||||
var musicPath = resolveMusicPath(musicSuffix, isStarting, isEnding);
|
var musicPath:Null<String> = resolveMusicPath(musicSuffix, isStarting, isEnding);
|
||||||
var onComplete = null;
|
var onComplete:() -> Void = () -> {};
|
||||||
|
|
||||||
if (isStarting)
|
if (isStarting)
|
||||||
{
|
{
|
||||||
if (musicPath == null)
|
if (musicPath == null)
|
||||||
{
|
{
|
||||||
|
// Looked for starting music and didn't find it. Use middle music instead.
|
||||||
isStarting = false;
|
isStarting = false;
|
||||||
musicPath = resolveMusicPath(musicSuffix, isStarting, isEnding);
|
musicPath = resolveMusicPath(musicSuffix, isStarting, isEnding);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
onComplete = function() {
|
onComplete = function() {
|
||||||
isStarting = false;
|
isStarting = true;
|
||||||
// We need to force to ensure that the non-starting music plays.
|
// We need to force to ensure that the non-starting music plays.
|
||||||
startDeathMusic(1.0, true);
|
startDeathMusic(1.0, true);
|
||||||
};
|
};
|
||||||
|
@ -359,13 +382,16 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
|
|
||||||
if (musicPath == null)
|
if (musicPath == null)
|
||||||
{
|
{
|
||||||
trace('Could not find game over music!');
|
FlxG.log.warn('[GAMEOVER] Could not find game over music at path ($musicPath)!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (gameOverMusic == null || !gameOverMusic.playing || force)
|
else if (gameOverMusic == null || !gameOverMusic.playing || force)
|
||||||
{
|
{
|
||||||
if (gameOverMusic != null) gameOverMusic.stop();
|
if (gameOverMusic != null) gameOverMusic.stop();
|
||||||
|
|
||||||
gameOverMusic = FunkinSound.load(musicPath);
|
gameOverMusic = FunkinSound.load(musicPath);
|
||||||
|
if (gameOverMusic == null) return;
|
||||||
|
|
||||||
gameOverMusic.volume = startingVolume;
|
gameOverMusic.volume = startingVolume;
|
||||||
gameOverMusic.looped = !(isEnding || isStarting);
|
gameOverMusic.looped = !(isEnding || isStarting);
|
||||||
gameOverMusic.onComplete = onComplete;
|
gameOverMusic.onComplete = onComplete;
|
||||||
|
@ -378,13 +404,11 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static var blueballed:Bool = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play the sound effect that occurs when
|
* Play the sound effect that occurs when
|
||||||
* boyfriend's testicles get utterly annihilated.
|
* boyfriend's testicles get utterly annihilated.
|
||||||
*/
|
*/
|
||||||
public static function playBlueBalledSFX()
|
public static function playBlueBalledSFX():Void
|
||||||
{
|
{
|
||||||
blueballed = true;
|
blueballed = true;
|
||||||
if (Assets.exists(Paths.sound('gameplay/gameover/fnf_loss_sfx' + blueBallSuffix)))
|
if (Assets.exists(Paths.sound('gameplay/gameover/fnf_loss_sfx' + blueBallSuffix)))
|
||||||
|
@ -403,7 +427,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
* Week 7-specific hardcoded behavior, to play a custom death quote.
|
* Week 7-specific hardcoded behavior, to play a custom death quote.
|
||||||
* TODO: Make this a module somehow.
|
* TODO: Make this a module somehow.
|
||||||
*/
|
*/
|
||||||
function playJeffQuote()
|
function playJeffQuote():Void
|
||||||
{
|
{
|
||||||
var randomCensor:Array<Int> = [];
|
var randomCensor:Array<Int> = [];
|
||||||
|
|
||||||
|
@ -418,20 +442,27 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function destroy()
|
public override function destroy():Void
|
||||||
{
|
{
|
||||||
super.destroy();
|
super.destroy();
|
||||||
if (gameOverMusic != null) gameOverMusic.stop();
|
if (gameOverMusic != null)
|
||||||
gameOverMusic = null;
|
{
|
||||||
|
gameOverMusic.stop();
|
||||||
|
gameOverMusic = null;
|
||||||
|
}
|
||||||
|
blueballed = false;
|
||||||
instance = null;
|
instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function toString():String
|
public override function toString():String
|
||||||
{
|
{
|
||||||
return "GameOverSubState";
|
return 'GameOverSubState';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters used to instantiate a GameOverSubState.
|
||||||
|
*/
|
||||||
typedef GameOverParams =
|
typedef GameOverParams =
|
||||||
{
|
{
|
||||||
var isChartingMode:Bool;
|
var isChartingMode:Bool;
|
||||||
|
|
|
@ -1499,7 +1499,7 @@ class PlayState extends MusicBeatSubState
|
||||||
public function resetCameraZoom():Void
|
public function resetCameraZoom():Void
|
||||||
{
|
{
|
||||||
// Apply camera zoom level from stage data.
|
// Apply camera zoom level from stage data.
|
||||||
defaultCameraZoom = currentStage.camZoom;
|
defaultCameraZoom = currentStage?.camZoom ?? 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2712,7 +2712,12 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
if (targetSongId == null)
|
if (targetSongId == null)
|
||||||
{
|
{
|
||||||
FunkinSound.playMusic('freakyMenu');
|
FunkinSound.playMusic('freakyMenu',
|
||||||
|
{
|
||||||
|
startingVolume: 0.0,
|
||||||
|
overrideExisting: true,
|
||||||
|
restartTrack: false
|
||||||
|
});
|
||||||
|
|
||||||
// transIn = FlxTransitionableState.defaultTransIn;
|
// transIn = FlxTransitionableState.defaultTransIn;
|
||||||
// transOut = FlxTransitionableState.defaultTransOut;
|
// transOut = FlxTransitionableState.defaultTransOut;
|
||||||
|
@ -2993,7 +2998,10 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
public function resetCamera():Void
|
public function resetCamera():Void
|
||||||
{
|
{
|
||||||
FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.04);
|
// Apply camera zoom level from stage data.
|
||||||
|
defaultCameraZoom = currentStage?.camZoom ?? 1.0;
|
||||||
|
|
||||||
|
FlxG.camera.follow(cameraFollowPoint, LOCKON, Constants.DEFAULT_CAMERA_FOLLOW_RATE);
|
||||||
FlxG.camera.targetOffset.set();
|
FlxG.camera.targetOffset.set();
|
||||||
FlxG.camera.zoom = defaultCameraZoom;
|
FlxG.camera.zoom = defaultCameraZoom;
|
||||||
// Snap the camera to the follow point immediately.
|
// Snap the camera to the follow point immediately.
|
||||||
|
|
|
@ -5,12 +5,13 @@ package funkin.play;
|
||||||
*
|
*
|
||||||
* TODO: Add getters/setters for all these properties to validate them.
|
* TODO: Add getters/setters for all these properties to validate them.
|
||||||
*/
|
*/
|
||||||
|
@:nullSafety
|
||||||
class PlayStatePlaylist
|
class PlayStatePlaylist
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Whether the game is currently in Story Mode. If false, we are in Free Play Mode.
|
* Whether the game is currently in Story Mode. If false, we are in Free Play Mode.
|
||||||
*/
|
*/
|
||||||
public static var isStoryMode(default, default):Bool = false;
|
public static var isStoryMode:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The loist of upcoming songs to be played.
|
* The loist of upcoming songs to be played.
|
||||||
|
@ -31,8 +32,9 @@ class PlayStatePlaylist
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The internal ID of the current playlist, for example `week4` or `weekend-1`.
|
* The internal ID of the current playlist, for example `week4` or `weekend-1`.
|
||||||
|
* @default `null`, used when no playlist is loaded
|
||||||
*/
|
*/
|
||||||
public static var campaignId:String = 'unknown';
|
public static var campaignId:Null<String> = null;
|
||||||
|
|
||||||
public static var campaignDifficulty:String = Constants.DEFAULT_DIFFICULTY;
|
public static var campaignDifficulty:String = Constants.DEFAULT_DIFFICULTY;
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ class PlayStatePlaylist
|
||||||
playlistSongIds = [];
|
playlistSongIds = [];
|
||||||
campaignScore = 0;
|
campaignScore = 0;
|
||||||
campaignTitle = 'UNKNOWN';
|
campaignTitle = 'UNKNOWN';
|
||||||
campaignId = 'unknown';
|
campaignId = null;
|
||||||
campaignDifficulty = Constants.DEFAULT_DIFFICULTY;
|
campaignDifficulty = Constants.DEFAULT_DIFFICULTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,7 +220,8 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
|
|
||||||
if (propSprite.frames == null || propSprite.frames.numFrames == 0)
|
if (propSprite.frames == null || propSprite.frames.numFrames == 0)
|
||||||
{
|
{
|
||||||
trace(' ERROR: Could not build texture for prop.');
|
@:privateAccess
|
||||||
|
trace(' ERROR: Could not build texture for prop. Check the asset path (${Paths.currentLevel ?? 'default'}, ${dataProp.assetPath}).');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,18 +6,15 @@ import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.FlxCamera;
|
import flixel.FlxCamera;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.FlxSubState;
|
import flixel.FlxSubState;
|
||||||
import flixel.graphics.FlxGraphic;
|
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import funkin.graphics.FunkinCamera;
|
|
||||||
import flixel.group.FlxSpriteGroup;
|
import flixel.group.FlxSpriteGroup;
|
||||||
import flixel.input.keyboard.FlxKey;
|
import flixel.input.keyboard.FlxKey;
|
||||||
|
import funkin.play.PlayStatePlaylist;
|
||||||
import flixel.input.mouse.FlxMouseEvent;
|
import flixel.input.mouse.FlxMouseEvent;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.math.FlxRect;
|
import flixel.math.FlxRect;
|
||||||
import flixel.sound.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.system.debug.log.LogStyle;
|
|
||||||
import flixel.system.FlxAssets.FlxSoundAsset;
|
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
|
@ -27,26 +24,19 @@ import flixel.util.FlxSort;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.audio.visualize.PolygonSpectogram;
|
import funkin.audio.visualize.PolygonSpectogram;
|
||||||
import funkin.audio.visualize.PolygonSpectogram;
|
|
||||||
import funkin.audio.VoicesGroup;
|
import funkin.audio.VoicesGroup;
|
||||||
import funkin.audio.waveform.WaveformSprite;
|
import funkin.audio.waveform.WaveformSprite;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
import funkin.data.song.SongData.SongCharacterData;
|
import funkin.data.song.SongData.SongCharacterData;
|
||||||
import funkin.data.song.SongData.SongCharacterData;
|
|
||||||
import funkin.data.song.SongData.SongChartData;
|
|
||||||
import funkin.data.song.SongData.SongChartData;
|
import funkin.data.song.SongData.SongChartData;
|
||||||
import funkin.data.song.SongData.SongEventData;
|
import funkin.data.song.SongData.SongEventData;
|
||||||
import funkin.data.song.SongData.SongEventData;
|
|
||||||
import funkin.data.song.SongData.SongMetadata;
|
import funkin.data.song.SongData.SongMetadata;
|
||||||
import funkin.data.song.SongData.SongMetadata;
|
|
||||||
import funkin.data.song.SongData.SongNoteData;
|
|
||||||
import funkin.data.song.SongData.SongNoteData;
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
import funkin.data.song.SongData.SongOffsets;
|
import funkin.data.song.SongData.SongOffsets;
|
||||||
import funkin.data.song.SongDataUtils;
|
import funkin.data.song.SongDataUtils;
|
||||||
import funkin.data.song.SongDataUtils;
|
|
||||||
import funkin.data.song.SongRegistry;
|
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.data.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
|
import funkin.graphics.FunkinCamera;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.input.Cursor;
|
import funkin.input.Cursor;
|
||||||
import funkin.input.TurboKeyHandler;
|
import funkin.input.TurboKeyHandler;
|
||||||
|
@ -62,8 +52,6 @@ import funkin.save.Save;
|
||||||
import funkin.ui.debug.charting.commands.AddEventsCommand;
|
import funkin.ui.debug.charting.commands.AddEventsCommand;
|
||||||
import funkin.ui.debug.charting.commands.AddNotesCommand;
|
import funkin.ui.debug.charting.commands.AddNotesCommand;
|
||||||
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
||||||
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
|
||||||
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
|
||||||
import funkin.ui.debug.charting.commands.CopyItemsCommand;
|
import funkin.ui.debug.charting.commands.CopyItemsCommand;
|
||||||
import funkin.ui.debug.charting.commands.CutItemsCommand;
|
import funkin.ui.debug.charting.commands.CutItemsCommand;
|
||||||
import funkin.ui.debug.charting.commands.DeselectAllItemsCommand;
|
import funkin.ui.debug.charting.commands.DeselectAllItemsCommand;
|
||||||
|
@ -96,6 +84,7 @@ import funkin.ui.debug.charting.toolboxes.ChartEditorOffsetsToolbox;
|
||||||
import funkin.ui.haxeui.components.CharacterPlayer;
|
import funkin.ui.haxeui.components.CharacterPlayer;
|
||||||
import funkin.ui.haxeui.HaxeUIState;
|
import funkin.ui.haxeui.HaxeUIState;
|
||||||
import funkin.ui.mainmenu.MainMenuState;
|
import funkin.ui.mainmenu.MainMenuState;
|
||||||
|
import funkin.ui.transition.LoadingState;
|
||||||
import funkin.util.Constants;
|
import funkin.util.Constants;
|
||||||
import funkin.util.FileUtil;
|
import funkin.util.FileUtil;
|
||||||
import funkin.util.logging.CrashHandler;
|
import funkin.util.logging.CrashHandler;
|
||||||
|
@ -120,7 +109,6 @@ import haxe.ui.containers.Grid;
|
||||||
import haxe.ui.containers.HBox;
|
import haxe.ui.containers.HBox;
|
||||||
import haxe.ui.containers.menus.Menu;
|
import haxe.ui.containers.menus.Menu;
|
||||||
import haxe.ui.containers.menus.MenuBar;
|
import haxe.ui.containers.menus.MenuBar;
|
||||||
import haxe.ui.containers.menus.MenuBar;
|
|
||||||
import haxe.ui.containers.menus.MenuCheckBox;
|
import haxe.ui.containers.menus.MenuCheckBox;
|
||||||
import haxe.ui.containers.menus.MenuItem;
|
import haxe.ui.containers.menus.MenuItem;
|
||||||
import haxe.ui.containers.ScrollView;
|
import haxe.ui.containers.ScrollView;
|
||||||
|
@ -131,7 +119,6 @@ import haxe.ui.core.Screen;
|
||||||
import haxe.ui.events.DragEvent;
|
import haxe.ui.events.DragEvent;
|
||||||
import haxe.ui.events.MouseEvent;
|
import haxe.ui.events.MouseEvent;
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
import haxe.ui.events.UIEvent;
|
|
||||||
import haxe.ui.focus.FocusManager;
|
import haxe.ui.focus.FocusManager;
|
||||||
import haxe.ui.Toolkit;
|
import haxe.ui.Toolkit;
|
||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
|
@ -5330,30 +5317,31 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
this.error("Could Not Playtest", 'Got an error trying to playtest the song.\n${e}');
|
this.error('Could Not Playtest', 'Got an error trying to playtest the song.\n${e}');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Rework asset system so we can remove this.
|
// TODO: Rework asset system so we can remove this jank.
|
||||||
switch (currentSongStage)
|
switch (currentSongStage)
|
||||||
{
|
{
|
||||||
case 'mainStage':
|
case 'mainStage':
|
||||||
Paths.setCurrentLevel('week1');
|
PlayStatePlaylist.campaignId = 'week1';
|
||||||
case 'spookyMansion':
|
case 'spookyMansion':
|
||||||
Paths.setCurrentLevel('week2');
|
PlayStatePlaylist.campaignId = 'week2';
|
||||||
case 'phillyTrain':
|
case 'phillyTrain':
|
||||||
Paths.setCurrentLevel('week3');
|
PlayStatePlaylist.campaignId = 'week3';
|
||||||
case 'limoRide':
|
case 'limoRide':
|
||||||
Paths.setCurrentLevel('week4');
|
PlayStatePlaylist.campaignId = 'week4';
|
||||||
case 'mallXmas' | 'mallEvil':
|
case 'mallXmas' | 'mallEvil':
|
||||||
Paths.setCurrentLevel('week5');
|
PlayStatePlaylist.campaignId = 'week5';
|
||||||
case 'school' | 'schoolEvil':
|
case 'school' | 'schoolEvil':
|
||||||
Paths.setCurrentLevel('week6');
|
PlayStatePlaylist.campaignId = 'week6';
|
||||||
case 'tankmanBattlefield':
|
case 'tankmanBattlefield':
|
||||||
Paths.setCurrentLevel('week7');
|
PlayStatePlaylist.campaignId = 'week7';
|
||||||
case 'phillyStreets' | 'phillyBlazin' | 'phillyBlazin2':
|
case 'phillyStreets' | 'phillyBlazin' | 'phillyBlazin2':
|
||||||
Paths.setCurrentLevel('weekend1');
|
PlayStatePlaylist.campaignId = 'weekend1';
|
||||||
}
|
}
|
||||||
|
Paths.setCurrentLevel(PlayStatePlaylist.campaignId);
|
||||||
|
|
||||||
subStateClosed.add(reviveUICamera);
|
subStateClosed.add(reviveUICamera);
|
||||||
subStateClosed.add(resetConductorAfterTest);
|
subStateClosed.add(resetConductorAfterTest);
|
||||||
|
@ -5361,7 +5349,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
FlxTransitionableState.skipNextTransIn = false;
|
FlxTransitionableState.skipNextTransIn = false;
|
||||||
FlxTransitionableState.skipNextTransOut = false;
|
FlxTransitionableState.skipNextTransOut = false;
|
||||||
|
|
||||||
var targetState = new PlayState(
|
var targetStateParams =
|
||||||
{
|
{
|
||||||
targetSong: targetSong,
|
targetSong: targetSong,
|
||||||
targetDifficulty: selectedDifficulty,
|
targetDifficulty: selectedDifficulty,
|
||||||
|
@ -5372,14 +5360,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
startTimestamp: startTimestamp,
|
startTimestamp: startTimestamp,
|
||||||
playbackRate: playbackRate,
|
playbackRate: playbackRate,
|
||||||
overrideMusic: true,
|
overrideMusic: true,
|
||||||
});
|
};
|
||||||
|
|
||||||
// Override music.
|
// Override music.
|
||||||
if (audioInstTrack != null)
|
if (audioInstTrack != null)
|
||||||
{
|
{
|
||||||
FlxG.sound.music = audioInstTrack;
|
FlxG.sound.music = audioInstTrack;
|
||||||
}
|
}
|
||||||
targetState.vocals = audioVocalTrackGroup;
|
|
||||||
|
|
||||||
// Kill and replace the UI camera so it doesn't get destroyed during the state transition.
|
// Kill and replace the UI camera so it doesn't get destroyed during the state transition.
|
||||||
uiCamera.kill();
|
uiCamera.kill();
|
||||||
|
@ -5389,7 +5376,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
this.persistentUpdate = false;
|
this.persistentUpdate = false;
|
||||||
this.persistentDraw = false;
|
this.persistentDraw = false;
|
||||||
stopWelcomeMusic();
|
stopWelcomeMusic();
|
||||||
openSubState(targetState);
|
|
||||||
|
LoadingState.loadPlayState(targetStateParams, false, true, function(targetState) {
|
||||||
|
targetState.vocals = audioVocalTrackGroup;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -179,7 +179,7 @@ class FreeplayState extends MusicBeatSubState
|
||||||
|
|
||||||
#if discord_rpc
|
#if discord_rpc
|
||||||
// Updating Discord Rich Presence
|
// Updating Discord Rich Presence
|
||||||
DiscordClient.changePresence("In the Menus", null);
|
DiscordClient.changePresence('In the Menus', null);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
var isDebug:Bool = false;
|
var isDebug:Bool = false;
|
||||||
|
@ -188,14 +188,19 @@ class FreeplayState extends MusicBeatSubState
|
||||||
isDebug = true;
|
isDebug = true;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
FunkinSound.playMusic('freakyMenu');
|
FunkinSound.playMusic('freakyMenu',
|
||||||
|
{
|
||||||
|
startingVolume: 0.0,
|
||||||
|
overrideExisting: true,
|
||||||
|
restartTrack: false
|
||||||
|
});
|
||||||
|
|
||||||
// Add a null entry that represents the RANDOM option
|
// Add a null entry that represents the RANDOM option
|
||||||
songs.push(null);
|
songs.push(null);
|
||||||
|
|
||||||
// TODO: This makes custom variations disappear from Freeplay. Figure out a better solution later.
|
// TODO: This makes custom variations disappear from Freeplay. Figure out a better solution later.
|
||||||
// Default character (BF) shows default and Erect variations. Pico shows only Pico variations.
|
// Default character (BF) shows default and Erect variations. Pico shows only Pico variations.
|
||||||
displayedVariations = (currentCharacter == "bf") ? [Constants.DEFAULT_VARIATION, "erect"] : [currentCharacter];
|
displayedVariations = (currentCharacter == 'bf') ? [Constants.DEFAULT_VARIATION, 'erect'] : [currentCharacter];
|
||||||
|
|
||||||
// programmatically adds the songs via LevelRegistry and SongRegistry
|
// programmatically adds the songs via LevelRegistry and SongRegistry
|
||||||
for (levelId in LevelRegistry.instance.listBaseGameLevelIds())
|
for (levelId in LevelRegistry.instance.listBaseGameLevelIds())
|
||||||
|
@ -205,7 +210,7 @@ class FreeplayState extends MusicBeatSubState
|
||||||
var song:Song = SongRegistry.instance.fetchEntry(songId);
|
var song:Song = SongRegistry.instance.fetchEntry(songId);
|
||||||
|
|
||||||
// Only display songs which actually have available charts for the current character.
|
// Only display songs which actually have available charts for the current character.
|
||||||
var availableDifficultiesForSong = song.listDifficulties(displayedVariations);
|
var availableDifficultiesForSong:Array<String> = song.listDifficulties(displayedVariations);
|
||||||
if (availableDifficultiesForSong.length == 0) continue;
|
if (availableDifficultiesForSong.length == 0) continue;
|
||||||
|
|
||||||
songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations));
|
songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations));
|
||||||
|
@ -1226,7 +1231,12 @@ class FreeplayState extends MusicBeatSubState
|
||||||
// TODO: Stream the instrumental of the selected song?
|
// TODO: Stream the instrumental of the selected song?
|
||||||
if (prevSelected == 0)
|
if (prevSelected == 0)
|
||||||
{
|
{
|
||||||
FunkinSound.playMusic('freakyMenu');
|
FunkinSound.playMusic('freakyMenu',
|
||||||
|
{
|
||||||
|
startingVolume: 0.0,
|
||||||
|
overrideExisting: true,
|
||||||
|
restartTrack: false
|
||||||
|
});
|
||||||
FlxG.sound.music.fadeIn(2, 0, 0.8);
|
FlxG.sound.music.fadeIn(2, 0, 0.8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,12 @@ class MainMenuState extends MusicBeatState
|
||||||
|
|
||||||
function playMenuMusic():Void
|
function playMenuMusic():Void
|
||||||
{
|
{
|
||||||
FunkinSound.playMusic('freakyMenu');
|
FunkinSound.playMusic('freakyMenu',
|
||||||
|
{
|
||||||
|
startingVolume: 0.0,
|
||||||
|
overrideExisting: true,
|
||||||
|
restartTrack: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetCamStuff()
|
function resetCamStuff()
|
||||||
|
|
|
@ -235,7 +235,12 @@ class StoryMenuState extends MusicBeatState
|
||||||
|
|
||||||
function playMenuMusic():Void
|
function playMenuMusic():Void
|
||||||
{
|
{
|
||||||
FunkinSound.playMusic('freakyMenu');
|
FunkinSound.playMusic('freakyMenu',
|
||||||
|
{
|
||||||
|
startingVolume: 0.0,
|
||||||
|
overrideExisting: true,
|
||||||
|
restartTrack: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateData():Void
|
function updateData():Void
|
||||||
|
|
|
@ -220,9 +220,14 @@ class TitleState extends MusicBeatState
|
||||||
|
|
||||||
function playMenuMusic():Void
|
function playMenuMusic():Void
|
||||||
{
|
{
|
||||||
var shouldFadeIn = (FlxG.sound.music == null);
|
var shouldFadeIn:Bool = (FlxG.sound.music == null);
|
||||||
// Load music. Includes logic to handle BPM changes.
|
// Load music. Includes logic to handle BPM changes.
|
||||||
FunkinSound.playMusic('freakyMenu', 0.0, false, true);
|
FunkinSound.playMusic('freakyMenu',
|
||||||
|
{
|
||||||
|
startingVolume: 0.0,
|
||||||
|
overrideExisting: true,
|
||||||
|
restartTrack: true
|
||||||
|
});
|
||||||
// Fade from 0.0 to 0.7 over 4 seconds
|
// Fade from 0.0 to 0.7 over 4 seconds
|
||||||
if (shouldFadeIn) FlxG.sound.music.fadeIn(4.0, 0.0, 1.0);
|
if (shouldFadeIn) FlxG.sound.music.fadeIn(4.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,12 @@ import openfl.filters.ShaderFilter;
|
||||||
import openfl.utils.Assets;
|
import openfl.utils.Assets;
|
||||||
import flixel.util.typeLimit.NextState;
|
import flixel.util.typeLimit.NextState;
|
||||||
|
|
||||||
class LoadingState extends MusicBeatState
|
class LoadingState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
inline static var MIN_TIME = 1.0;
|
inline static var MIN_TIME = 1.0;
|
||||||
|
|
||||||
|
var asSubState:Bool = false;
|
||||||
|
|
||||||
var target:NextState;
|
var target:NextState;
|
||||||
var playParams:Null<PlayStateParams>;
|
var playParams:Null<PlayStateParams>;
|
||||||
var stopMusic:Bool = false;
|
var stopMusic:Bool = false;
|
||||||
|
@ -173,7 +175,16 @@ class LoadingState extends MusicBeatState
|
||||||
{
|
{
|
||||||
if (stopMusic && FlxG.sound.music != null) FlxG.sound.music.stop();
|
if (stopMusic && FlxG.sound.music != null) FlxG.sound.music.stop();
|
||||||
|
|
||||||
FlxG.switchState(target);
|
if (asSubState)
|
||||||
|
{
|
||||||
|
this.close();
|
||||||
|
// We will assume the target is a valid substate.
|
||||||
|
FlxG.state.openSubState(cast target);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.switchState(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static function getSongPath():String
|
static function getSongPath():String
|
||||||
|
@ -185,17 +196,41 @@ class LoadingState extends MusicBeatState
|
||||||
* Starts the transition to a new `PlayState` to start a new song.
|
* Starts the transition to a new `PlayState` to start a new song.
|
||||||
* First switches to the `LoadingState` if assets need to be loaded.
|
* First switches to the `LoadingState` if assets need to be loaded.
|
||||||
* @param params The parameters for the next `PlayState`.
|
* @param params The parameters for the next `PlayState`.
|
||||||
|
* @param asSubState Whether to open as a substate rather than switching to the `PlayState`.
|
||||||
* @param shouldStopMusic Whether to stop the current music while loading.
|
* @param shouldStopMusic Whether to stop the current music while loading.
|
||||||
*/
|
*/
|
||||||
public static function loadPlayState(params:PlayStateParams, shouldStopMusic = false):Void
|
public static function loadPlayState(params:PlayStateParams, shouldStopMusic = false, asSubState = false, ?onConstruct:PlayState->Void):Void
|
||||||
{
|
{
|
||||||
Paths.setCurrentLevel(PlayStatePlaylist.campaignId);
|
Paths.setCurrentLevel(PlayStatePlaylist.campaignId);
|
||||||
var playStateCtor:NextState = () -> new PlayState(params);
|
var playStateCtor:() -> PlayState = function() {
|
||||||
|
return new PlayState(params);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (onConstruct != null)
|
||||||
|
{
|
||||||
|
playStateCtor = function() {
|
||||||
|
var result = new PlayState(params);
|
||||||
|
onConstruct(result);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#if NO_PRELOAD_ALL
|
#if NO_PRELOAD_ALL
|
||||||
// Switch to loading state while we load assets (default on HTML5 target).
|
// Switch to loading state while we load assets (default on HTML5 target).
|
||||||
var loadStateCtor:NextState = () -> new LoadingState(playStateCtor, shouldStopMusic, params);
|
var loadStateCtor:NextState = function() {
|
||||||
FlxG.switchState(loadStateCtor);
|
var result = new LoadingState(playStateCtor, shouldStopMusic, params);
|
||||||
|
@:privateAccess
|
||||||
|
result.asSubState = asSubState;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (asSubState)
|
||||||
|
{
|
||||||
|
FlxG.state.openSubState(loadStateCtor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.switchState(loadStateCtor);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
// All assets preloaded, switch directly to play state (defualt on other targets).
|
// All assets preloaded, switch directly to play state (defualt on other targets).
|
||||||
if (shouldStopMusic && FlxG.sound.music != null)
|
if (shouldStopMusic && FlxG.sound.music != null)
|
||||||
|
@ -209,6 +244,34 @@ class LoadingState extends MusicBeatState
|
||||||
params.targetSong.cacheCharts(true);
|
params.targetSong.cacheCharts(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var shouldPreloadLevelAssets:Bool = !(params?.minimalMode ?? false);
|
||||||
|
|
||||||
|
if (shouldPreloadLevelAssets) preloadLevelAssets();
|
||||||
|
|
||||||
|
if (asSubState)
|
||||||
|
{
|
||||||
|
FlxG.state.openSubState(cast playStateCtor());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.switchState(playStateCtor);
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NO_PRELOAD_ALL
|
||||||
|
static function isSoundLoaded(path:String):Bool
|
||||||
|
{
|
||||||
|
return Assets.cache.hasSound(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function isLibraryLoaded(library:String):Bool
|
||||||
|
{
|
||||||
|
return Assets.getLibrary(library) != null;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static function preloadLevelAssets():Void
|
||||||
|
{
|
||||||
// TODO: This section is a hack! Redo this later when we have a proper asset caching system.
|
// TODO: This section is a hack! Redo this later when we have a proper asset caching system.
|
||||||
FunkinSprite.preparePurgeCache();
|
FunkinSprite.preparePurgeCache();
|
||||||
FunkinSprite.cacheTexture(Paths.image('combo'));
|
FunkinSprite.cacheTexture(Paths.image('combo'));
|
||||||
|
@ -241,7 +304,10 @@ class LoadingState extends MusicBeatState
|
||||||
// List all image assets in the level's library.
|
// List all image assets in the level's library.
|
||||||
// This is crude and I want to remove it when we have a proper asset caching system.
|
// This is crude and I want to remove it when we have a proper asset caching system.
|
||||||
// TODO: Get rid of this junk!
|
// TODO: Get rid of this junk!
|
||||||
var library = openfl.utils.Assets.getLibrary(PlayStatePlaylist.campaignId);
|
var library = PlayStatePlaylist.campaignId != null ? openfl.utils.Assets.getLibrary(PlayStatePlaylist.campaignId) : null;
|
||||||
|
|
||||||
|
if (library == null) return; // We don't need to do anymore precaching.
|
||||||
|
|
||||||
var assets = library.list(lime.utils.AssetType.IMAGE);
|
var assets = library.list(lime.utils.AssetType.IMAGE);
|
||||||
trace('Got ${assets.length} assets: ${assets}');
|
trace('Got ${assets.length} assets: ${assets}');
|
||||||
|
|
||||||
|
@ -272,20 +338,6 @@ class LoadingState extends MusicBeatState
|
||||||
// FunkinSprite.cacheAllSongTextures(stage)
|
// FunkinSprite.cacheAllSongTextures(stage)
|
||||||
|
|
||||||
FunkinSprite.purgeCache();
|
FunkinSprite.purgeCache();
|
||||||
|
|
||||||
FlxG.switchState(playStateCtor);
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NO_PRELOAD_ALL
|
|
||||||
static function isSoundLoaded(path:String):Bool
|
|
||||||
{
|
|
||||||
return Assets.cache.hasSound(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function isLibraryLoaded(library:String):Bool
|
|
||||||
{
|
|
||||||
return Assets.getLibrary(library) != null;
|
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|
|
@ -442,4 +442,10 @@ class Constants
|
||||||
* The vertical offset of the strumline from the top edge of the screen.
|
* The vertical offset of the strumline from the top edge of the screen.
|
||||||
*/
|
*/
|
||||||
public static final STRUMLINE_Y_OFFSET:Float = 24;
|
public static final STRUMLINE_Y_OFFSET:Float = 24;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rate at which the camera lerps to its target.
|
||||||
|
* 0.04 = 4% of distance per frame.
|
||||||
|
*/
|
||||||
|
public static final DEFAULT_CAMERA_FOLLOW_RATE:Float = 0.04;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue