diff --git a/Project.xml b/Project.xml
index 3f930bc73..93845756c 100644
--- a/Project.xml
+++ b/Project.xml
@@ -129,7 +129,7 @@
-
+
diff --git a/hmm.json b/hmm.json
index e92868545..84510a05a 100644
--- a/hmm.json
+++ b/hmm.json
@@ -68,7 +68,7 @@
"name": "hxcodec",
"type": "git",
"dir": null,
- "ref": "91adeec",
+ "ref": "14ef69f",
"url": "https://github.com/polybiusproxy/hxCodec"
},
{
@@ -118,4 +118,4 @@
"version": "0.2.2"
}
]
-}
\ No newline at end of file
+}
diff --git a/source/funkin/CutsceneAnimTestState.hx b/source/funkin/CutsceneAnimTestState.hx
deleted file mode 100644
index 7d6369c12..000000000
--- a/source/funkin/CutsceneAnimTestState.hx
+++ /dev/null
@@ -1,80 +0,0 @@
-package funkin;
-
-import flixel.FlxSprite;
-import flixel.FlxState;
-import flixel.addons.display.FlxGridOverlay;
-import flixel.group.FlxGroup.FlxTypedGroup;
-import flixel.math.FlxPoint;
-import flixel.text.FlxText;
-import flixel.util.FlxColor;
-import openfl.Assets;
-import openfl.display.BitmapData;
-import openfl.display.MovieClip;
-import openfl.display.Timeline;
-import openfl.geom.Matrix;
-import openfl.geom.Rectangle;
-
-class CutsceneAnimTestState extends FlxState
-{
- var cutsceneGroup:CutsceneCharacter;
-
- var curSelected:Int = 0;
- var debugTxt:FlxText;
-
- var funnySprite:FlxSprite = new FlxSprite();
- var clip:MovieClip;
-
- public function new()
- {
- super();
-
- var gridBG:FlxSprite = FlxGridOverlay.create(10, 10);
- gridBG.scrollFactor.set(0.5, 0.5);
- add(gridBG);
-
- debugTxt = new FlxText(900, 20, 0, "", 20);
- debugTxt.color = FlxColor.BLUE;
- add(debugTxt);
-
- clip = Assets.getMovieClip("tanky:");
- // clip.x = FlxG.width/2;
- // clip.y = FlxG.height/2;
- FlxG.stage.addChild(clip);
-
- var swagShit:MovieClip = Assets.getMovieClip('tankBG:');
- // swagShit.scaleX = 5;
-
- FlxG.stage.addChild(swagShit);
- swagShit.gotoAndStop(13);
-
- var swfMountain = new BitmapData(FlxG.width, FlxG.height, true, 0x00000000);
- swfMountain.draw(swagShit, swagShit.transform.matrix);
-
- var mountains:FlxSprite = new FlxSprite().loadGraphic(swfMountain);
- // add(mountains);
-
- FlxG.stage.removeChild(swagShit);
-
- funnySprite.x = FlxG.width / 2;
- funnySprite.y = FlxG.height / 2;
- add(funnySprite);
- }
-
- override function update(elapsed:Float)
- {
- super.update(elapsed);
-
- // jam sprite into top left corner
- var drawMatrix:Matrix = clip.transform.matrix;
- var bounds:Rectangle = clip.getBounds(null);
- drawMatrix.tx = -bounds.x;
- drawMatrix.ty = -bounds.y;
- // make bitmapdata only as big as it needs to be
- var funnyBmp:BitmapData = new BitmapData(Math.ceil(bounds.width), Math.ceil(bounds.height), true, 0x00000000);
- funnyBmp.draw(clip, drawMatrix, true);
- funnySprite.loadGraphic(funnyBmp);
- // jam sprite back into place lol
- funnySprite.offset.x = -bounds.x;
- funnySprite.offset.y = -bounds.y;
- }
-}
diff --git a/source/funkin/CutsceneCharacter.hx b/source/funkin/CutsceneCharacter.hx
deleted file mode 100644
index 67810bc30..000000000
--- a/source/funkin/CutsceneCharacter.hx
+++ /dev/null
@@ -1,75 +0,0 @@
-package funkin;
-
-import flixel.FlxSprite;
-import flixel.group.FlxGroup.FlxTypedGroup;
-import flixel.math.FlxPoint;
-
-class CutsceneCharacter extends FlxTypedGroup
-{
- public var coolPos:FlxPoint = FlxPoint.get();
- public var animShit:Map = new Map();
-
- var imageShit:String;
-
- public function new(x:Float, y:Float, imageShit:String)
- {
- super();
-
- coolPos.set(x, y);
-
- this.imageShit = imageShit;
- parseOffsets();
- createCutscene(0);
- }
-
- // shitshow, oh well
- var arrayLMFAOOOO:Array = [];
-
- function parseOffsets()
- {
- var splitShit:Array = CoolUtil.coolTextFile(Paths.file('images/cutsceneStuff/' + imageShit + "CutsceneOffsets.txt"));
-
- for (i in splitShit)
- {
- var xAndY:FlxPoint = FlxPoint.get();
- var dumbSplit:Array = i.split('---')[1].trim().split(' ');
- trace('cool split: ' + i.split('---')[1]);
- trace(dumbSplit);
- xAndY.set(Std.parseFloat(dumbSplit[0]), Std.parseFloat(dumbSplit[1]));
-
- animShit.set(i.split('---')[0].trim(), xAndY);
- arrayLMFAOOOO.push(i.split('---')[0].trim());
- }
-
- trace(animShit);
- }
-
- public function createCutscene(daNum:Int = 0)
- {
- var cutScene:FlxSprite = new FlxSprite(coolPos.x + animShit.get(arrayLMFAOOOO[daNum]).x, coolPos.y + animShit.get(arrayLMFAOOOO[daNum]).y);
- cutScene.frames = Paths.getSparrowAtlas('cutsceneStuff/' + imageShit + "-" + daNum);
- cutScene.animation.addByPrefix('weed', arrayLMFAOOOO[daNum], 24, false);
- cutScene.animation.play('weed');
- cutScene.antialiasing = true;
-
- cutScene.animation.finishCallback = function(anim:String)
- {
- cutScene.kill();
- cutScene.destroy();
- cutScene = null;
-
- if (daNum + 1 < arrayLMFAOOOO.length) createCutscene(daNum + 1);
- else
- ended();
- };
-
- add(cutScene);
- }
-
- public var onFinish:Void->Void;
-
- public function ended():Void
- {
- if (onFinish != null) onFinish();
- }
-}
diff --git a/source/funkin/play/cutscene/VanillaCutscenes.hx b/source/funkin/play/cutscene/VanillaCutscenes.hx
index a0cbd965b..a332d0795 100644
--- a/source/funkin/play/cutscene/VanillaCutscenes.hx
+++ b/source/funkin/play/cutscene/VanillaCutscenes.hx
@@ -1,13 +1,10 @@
package funkin.play.cutscene;
-// import hxcodec.flixel.FlxVideoSprite;
-// import hxcodec.flixel.FlxCutsceneState;
import flixel.FlxSprite;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
-import funkin.graphics.video.FlxVideo;
/**
* Static methods for playing cutscenes in the PlayState.
@@ -15,112 +12,46 @@ import funkin.graphics.video.FlxVideo;
*/
class VanillaCutscenes
{
- /**
- * Well, well, well, what have we got here?
- */
- public static function playUghCutscene():Void
- {
- playVideoCutscene('music/ughCutscene.mp4');
- }
-
- /**
- * Nice bars for an ugly, boring teenager!
- */
- public static function playGunsCutscene():Void
- {
- playVideoCutscene('music/gunsCutscene.mp4');
- }
-
- /**
- * Don't you have a school to shoot up?
- */
- public static function playStressCutscene():Void
- {
- playVideoCutscene('music/stressCutscene.mp4');
- }
-
static var blackScreen:FlxSprite;
- /**
- * Plays a cutscene from a video file, then starts the countdown once the video is done.
- * TODO: Cutscene is currently skipped on native platforms.
- */
- static function playVideoCutscene(path:String):Void
- {
- // Tell PlayState to stop the song until the video is done.
- PlayState.isInCutscene = true;
- PlayState.instance.camHUD.visible = false;
-
- // Display a black screen to hide the game while the video is playing.
- blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
- blackScreen.scrollFactor.set(0, 0);
- blackScreen.cameras = [PlayState.instance.camCutscene];
- PlayState.instance.add(blackScreen);
-
- #if html5
- // Video displays OVER the FlxState.
- vid = new FlxVideo(path);
- vid.finishCallback = finishCutscene.bind(0.5);
- #else
- // Video displays OVER the FlxState.
- // vid = new FlxVideoSprite(0, 0);
-
- vid.cameras = [PlayState.instance.camCutscene];
-
- PlayState.instance.add(vid);
-
- vid.playVideo(Paths.file(path), false);
- vid.onEndReached.add(finishCutscene.bind(0.5));
- #end
- }
-
- static var vid:#if html5 FlxVideo #else Dynamic /**FlxVideoSprite **/ #end;
+ static final TWEEN_DURATION:Float = 2.0;
/**
- * Does the cleanup to start the countdown after the video is done.
- * Gets called immediately if the video can't be played.
- */
- public static function finishCutscene(?transitionTime:Float = 2.5):Void
- {
- trace('ALERT: Finish cutscene called!');
-
- #if html5
- #else
- vid.stop();
- PlayState.instance.remove(vid);
- #end
-
- PlayState.instance.camHUD.visible = true;
-
- FlxTween.tween(blackScreen, {alpha: 0}, transitionTime,
- {
- ease: FlxEase.quadInOut,
- onComplete: function(twn:FlxTween) {
- PlayState.instance.remove(blackScreen);
- blackScreen = null;
- }
- });
- FlxTween.tween(FlxG.camera, {zoom: PlayState.defaultCameraZoom}, transitionTime,
- {
- ease: FlxEase.quadInOut,
- onComplete: function(twn:FlxTween) {
- PlayState.instance.startCountdown();
- }
- });
- }
-
- /**
- * FNF corruption mod???
+ * Plays the cutscene that appears at the start of Winter Horrorland.
+ * TODO: Move this to `winter-horrorland.hxc`
*/
public static function playHorrorStartCutscene():Void
{
- PlayState.isInCutscene = true;
+ PlayState.instance.isInCutscene = true;
PlayState.instance.camHUD.visible = false;
blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
blackScreen.scrollFactor.set(0, 0);
+ blackScreen.zIndex = 1000000;
PlayState.instance.add(blackScreen);
- new FlxTimer().start(0.1, _ -> finishCutscene(2.5));
+ new FlxTimer().start(0.1, function(_) {
+ trace('Playing horrorland cutscene...');
+ PlayState.instance.remove(blackScreen);
+
+ // Force set the camera position and zoom.
+ PlayState.instance.cameraFollowPoint.setPosition(400, -2050);
+ PlayState.instance.resetCamera();
+ FlxG.camera.zoom = 2.5;
+
+ // Play the Sound effect.
+ FlxG.sound.play(Paths.sound('Lights_Turn_On'), function() {
+ // Fade in the HUD.
+ trace('SFX done...');
+ PlayState.instance.camHUD.visible = true;
+ PlayState.instance.camHUD.alpha = 0.0; // Use alpha rather than visible to let us fade it in.
+ FlxTween.tween(PlayState.instance.camHUD, {alpha: 1.0}, TWEEN_DURATION, {ease: FlxEase.quadInOut});
+
+ // Start the countdown.
+ trace('Zoom out done...');
+ trace('Begin countdown (ends cutscene)');
+ PlayState.instance.startCountdown();
+ });
+ });
}
}
diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx
new file mode 100644
index 000000000..fe0cf9bbb
--- /dev/null
+++ b/source/funkin/play/cutscene/VideoCutscene.hx
@@ -0,0 +1,155 @@
+package funkin.play.cutscene;
+
+import funkin.play.PlayState;
+import flixel.FlxSprite;
+import flixel.tweens.FlxEase;
+import flixel.tweens.FlxTween;
+import flixel.util.FlxColor;
+import flixel.util.FlxTimer;
+#if html5
+import funkin.graphics.video.FlxVideo;
+#else
+import hxcodec.flixel.FlxVideoSprite;
+#end
+
+/**
+ * Assumes you are in the PlayState.
+ */
+class VideoCutscene
+{
+ static var blackScreen:FlxSprite;
+
+ /**
+ * Play a video cutscene.
+ * TODO: Currently this is hardcoded to start the countdown after the video is done.
+ * @param path The path to the video file. Use Paths.file(path) to get the correct path.
+ */
+ public static function play(filePath:String):Void
+ {
+ if (PlayState.instance == null) return;
+
+ if (!openfl.Assets.exists(filePath))
+ {
+ trace('ERROR: Video file does not exist: ${filePath}');
+ return;
+ }
+
+ // Trigger the cutscene. Don't play the song in the background.
+ PlayState.instance.isInCutscene = true;
+ PlayState.instance.camHUD.visible = false;
+ PlayState.instance.camCutscene.visible = true;
+
+ // Display a black screen to hide the game while the video is playing.
+ blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
+ blackScreen.scrollFactor.set(0, 0);
+ blackScreen.cameras = [PlayState.instance.camCutscene];
+ PlayState.instance.add(blackScreen);
+
+ #if html5
+ playVideoHTML5(filePath);
+ #else
+ playVideoNative(filePath);
+ #end
+ }
+
+ public static function isPlaying():Bool
+ {
+ return vid != null;
+ }
+
+ #if html5
+ static var vid:FlxVideo;
+
+ static function playVideoHTML5(filePath:String):Void
+ {
+ // Video displays OVER the FlxState.
+ vid = new FlxVideo(filePath);
+ if (vid != null)
+ {
+ vid.zIndex = 0;
+
+ vid.finishCallback = finishVideo.bind(0.5);
+
+ vid.cameras = [PlayState.instance.camCutscene];
+
+ PlayState.instance.add(vid);
+
+ PlayState.instance.refresh();
+ }
+ else
+ {
+ trace('ALERT: Video is null! Could not play cutscene!');
+ }
+ }
+ #else
+ static var vid:FlxVideoSprite;
+
+ static function playVideoNative(filePath:String):Void
+ {
+ // Video displays OVER the FlxState.
+ vid = new FlxVideoSprite(0, 0);
+
+ if (vid != null)
+ {
+ vid.zIndex = 0;
+ vid.onEndReached.add(finishVideo.bind(0.5));
+
+ vid.cameras = [PlayState.instance.camCutscene];
+
+ PlayState.instance.add(vid);
+
+ PlayState.instance.refresh();
+ vid.playVideo(filePath, false);
+ }
+ else
+ {
+ trace('ALERT: Video is null! Could not play cutscene!');
+ }
+ }
+ #end
+
+ public static function finishVideo(?transitionTime:Float = 0.5):Void
+ {
+ trace('ALERT: Finish video cutscene called!');
+
+ #if html5
+ if (vid != null)
+ {
+ PlayState.instance.remove(vid);
+ }
+ #else
+ if (vid != null)
+ {
+ vid.stop();
+ PlayState.instance.remove(vid);
+ }
+ #end
+ vid.destroy();
+ vid = null;
+
+ PlayState.instance.camCutscene.visible = true;
+ PlayState.instance.camHUD.visible = true;
+
+ FlxTween.tween(blackScreen, {alpha: 0}, transitionTime,
+ {
+ ease: FlxEase.quadInOut,
+ onComplete: function(twn:FlxTween) {
+ PlayState.instance.remove(blackScreen);
+ blackScreen = null;
+ }
+ });
+ FlxTween.tween(FlxG.camera, {zoom: PlayState.instance.defaultCameraZoom}, transitionTime,
+ {
+ ease: FlxEase.quadInOut,
+ onComplete: function(twn:FlxTween) {
+ PlayState.instance.startCountdown();
+ }
+ });
+ }
+}
+
+/*
+ trace('Video playback failed (${e})');
+ vid = null;
+ finishCutscene(0.5);
+ */