diff --git a/assets b/assets index 371cce1fd..8fea0bf1f 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 371cce1fdc44914ddc3a5327e996cece4e676715 +Subproject commit 8fea0bf1fe07b6dd0efb8ecf46dc8091b0177007 diff --git a/source/funkin/effects/IntervalShake.hx b/source/funkin/effects/IntervalShake.hx new file mode 100644 index 000000000..545739cc3 --- /dev/null +++ b/source/funkin/effects/IntervalShake.hx @@ -0,0 +1,240 @@ +package funkin.effects; + +import flixel.FlxObject; +import flixel.util.FlxDestroyUtil.IFlxDestroyable; +import flixel.util.FlxPool; +import flixel.util.FlxTimer; +import flixel.math.FlxPoint; +import flixel.util.FlxAxes; +import flixel.tweens.FlxEase.EaseFunction; +import flixel.math.FlxMath; + +/** + * pretty much a copy of FlxFlicker geared towards making sprites + * shake around at a set interval and slow down over time. + */ +class IntervalShake implements IFlxDestroyable +{ + static var _pool:FlxPool = new FlxPool(IntervalShake.new); + + /** + * Internal map for looking up which objects are currently shaking and getting their shake data. + */ + static var _boundObjects:Map = new Map(); + + /** + * An effect that shakes the sprite on a set interval and a starting intensity that goes down over time. + * + * @param Object The object to shake. + * @param Duration How long to shake for (in seconds). `0` means "forever". + * @param Interval In what interval to update the shake position. Set to `FlxG.elapsed` if `<= 0`! + * @param StartIntensity The starting intensity of the shake. + * @param EndIntensity The ending intensity of the shake. + * @param Ease Control the easing of the intensity over the shake. + * @param CompletionCallback Callback on shake completion + * @param ProgressCallback Callback on each shake interval + * @return The `IntervalShake` object. `IntervalShake`s are pooled internally, so beware of storing references. + */ + public static function shake(Object:FlxObject, Duration:Float = 1, Interval:Float = 0.04, StartIntensity:Float = 0, EndIntensity:Float = 0, + Ease:EaseFunction, ?CompletionCallback:IntervalShake->Void, ?ProgressCallback:IntervalShake->Void):IntervalShake + { + if (isShaking(Object)) + { + // if (ForceRestart) + // { + // stopShaking(Object); + // } + // else + // { + // Ignore this call if object is already flickering. + return _boundObjects[Object]; + // } + } + + if (Interval <= 0) + { + Interval = FlxG.elapsed; + } + + var shake:IntervalShake = _pool.get(); + shake.start(Object, Duration, Interval, StartIntensity, EndIntensity, Ease, CompletionCallback, ProgressCallback); + return _boundObjects[Object] = shake; + } + + /** + * Returns whether the object is shaking or not. + * + * @param Object The object to test. + */ + public static function isShaking(Object:FlxObject):Bool + { + return _boundObjects.exists(Object); + } + + /** + * Stops shaking the object. + * + * @param Object The object to stop shaking. + */ + public static function stopShaking(Object:FlxObject):Void + { + var boundShake:IntervalShake = _boundObjects[Object]; + if (boundShake != null) + { + boundShake.stop(); + } + } + + /** + * The shaking object. + */ + public var object(default, null):FlxObject; + + /** + * The shaking timer. You can check how many seconds has passed since shaking started etc. + */ + public var timer(default, null):FlxTimer; + + /** + * The starting intensity of the shake. + */ + public var startIntensity(default, null):Float; + + /** + * The ending intensity of the shake. + */ + public var endIntensity(default, null):Float; + + /** + * How long to shake for (in seconds). `0` means "forever". + */ + public var duration(default, null):Float; + + /** + * The interval of the shake. + */ + public var interval(default, null):Float; + + /** + * Defines on what axes to `shake()`. Default value is `XY` / both. + */ + public var axes(default, null):FlxAxes; + + /** + * Defines the initial position of the object at the beginning of the shake effect. + */ + public var initialOffset(default, null):FlxPoint; + + /** + * The callback that will be triggered after the shake has completed. + */ + public var completionCallback(default, null):IntervalShake->Void; + + /** + * The callback that will be triggered every time the object shakes. + */ + public var progressCallback(default, null):IntervalShake->Void; + + /** + * The easing of the intensity over the shake. + */ + public var ease(default, null):EaseFunction; + + /** + * Nullifies the references to prepare object for reuse and avoid memory leaks. + */ + public function destroy():Void + { + object = null; + timer = null; + ease = null; + completionCallback = null; + progressCallback = null; + } + + /** + * Starts shaking behavior. + */ + function start(Object:FlxObject, Duration:Float = 1, Interval:Float = 0.04, StartIntensity:Float = 0, EndIntensity:Float = 0, Ease:EaseFunction, + ?CompletionCallback:IntervalShake->Void, ?ProgressCallback:IntervalShake->Void):Void + { + object = Object; + duration = Duration; + interval = Interval; + completionCallback = CompletionCallback; + startIntensity = StartIntensity; + endIntensity = EndIntensity; + initialOffset = new FlxPoint(Object.x, Object.y); + ease = Ease; + axes = FlxAxes.XY; + _secondsSinceStart = 0; + timer = new FlxTimer().start(interval, shakeProgress, Std.int(duration / interval)); + } + + /** + * Prematurely ends shaking. + */ + public function stop():Void + { + timer.cancel(); + // object.visible = true; + object.x = initialOffset.x; + object.y = initialOffset.y; + release(); + } + + /** + * Unbinds the object from shaking and releases it into pool for reuse. + */ + function release():Void + { + _boundObjects.remove(object); + _pool.put(this); + } + + public var _secondsSinceStart(default, null):Float = 0; + + public var scale(default, null):Float = 0; + + /** + * Just a helper function for shake() to update object's position. + */ + function shakeProgress(timer:FlxTimer):Void + { + _secondsSinceStart += interval; + scale = _secondsSinceStart / duration; + if (ease != null) + { + scale = 1 - ease(scale); + // trace(scale); + } + + var curIntensity:Float = 0; + curIntensity = FlxMath.lerp(endIntensity, startIntensity, scale); + + if (axes.x) object.x = initialOffset.x + FlxG.random.float((-curIntensity) * object.width, (curIntensity) * object.width); + if (axes.y) object.y = initialOffset.y + FlxG.random.float((-curIntensity) * object.width, (curIntensity) * object.width); + + // object.visible = !object.visible; + + if (progressCallback != null) progressCallback(this); + + if (timer.loops > 0 && timer.loopsLeft == 0) + { + object.x = initialOffset.x; + object.y = initialOffset.y; + if (completionCallback != null) + { + completionCallback(this); + } + + if (this.timer == timer) release(); + } + } + + /** + * Internal constructor. Use static methods. + */ + @:keep + function new() {} +} diff --git a/source/funkin/ui/freeplay/CapsuleText.hx b/source/funkin/ui/freeplay/CapsuleText.hx index 3a520e015..c3fd51d1f 100644 --- a/source/funkin/ui/freeplay/CapsuleText.hx +++ b/source/funkin/ui/freeplay/CapsuleText.hx @@ -4,6 +4,12 @@ import openfl.filters.BitmapFilterQuality; import flixel.text.FlxText; import flixel.group.FlxSpriteGroup; import funkin.graphics.shaders.GaussianBlurShader; +import funkin.graphics.shaders.LeftMaskShader; +import flixel.math.FlxRect; +import flixel.tweens.FlxEase; +import flixel.util.FlxTimer; +import flixel.tweens.FlxTween; +import openfl.display.BlendMode; class CapsuleText extends FlxSpriteGroup { @@ -13,6 +19,15 @@ class CapsuleText extends FlxSpriteGroup public var text(default, set):String; + var maskShaderSongName:LeftMaskShader = new LeftMaskShader(); + + public var clipWidth(default, set):Int = 255; + + public var tooLong:Bool = false; + + // 255, 27 normal + // 220, 27 favourited + public function new(x:Float, y:Float, songTitle:String, size:Float) { super(x, y); @@ -36,6 +51,30 @@ class CapsuleText extends FlxSpriteGroup return text; } + // ???? none + // 255, 27 normal + // 220, 27 favourited + + function set_clipWidth(value:Int):Int + { + resetText(); + if (whiteText.width > value) + { + tooLong = true; + + blurredText.clipRect = new FlxRect(0, 0, value, blurredText.height); + whiteText.clipRect = new FlxRect(0, 0, value, whiteText.height); + } + else + { + tooLong = false; + + blurredText.clipRect = null; + whiteText.clipRect = null; + } + return clipWidth = value; + } + function set_text(value:String):String { if (value == null) return value; @@ -51,6 +90,102 @@ class CapsuleText extends FlxSpriteGroup new openfl.filters.GlowFilter(0x00ccff, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM), // new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW) ]; + return text = value; } + + var moveTimer:FlxTimer = new FlxTimer(); + var moveTween:FlxTween; + + public function initMove():Void + { + moveTimer.start(0.6, (timer) -> { + moveTextRight(); + }); + } + + function moveTextRight():Void + { + var distToMove:Float = whiteText.width - clipWidth; + moveTween = FlxTween.tween(whiteText.offset, {x: distToMove}, 2, + { + onUpdate: function(_) { + whiteText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + blurredText.offset = whiteText.offset; + blurredText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, blurredText.height); + }, + onComplete: function(_) { + moveTimer.start(0.3, (timer) -> { + moveTextLeft(); + }); + }, + ease: FlxEase.sineInOut + }); + } + + function moveTextLeft():Void + { + moveTween = FlxTween.tween(whiteText.offset, {x: 0}, 2, + { + onUpdate: function(_) { + whiteText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + blurredText.offset = whiteText.offset; + blurredText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, blurredText.height); + }, + onComplete: function(_) { + moveTimer.start(0.3, (timer) -> { + moveTextRight(); + }); + }, + ease: FlxEase.sineInOut + }); + } + + public function resetText():Void + { + if (moveTween != null) moveTween.cancel(); + if (moveTimer != null) moveTimer.cancel(); + whiteText.offset.x = 0; + whiteText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + blurredText.clipRect = new FlxRect(whiteText.offset.x, 0, clipWidth, whiteText.height); + } + + var flickerState:Bool = false; + var flickerTimer:FlxTimer; + + public function flickerText():Void + { + resetText(); + flickerTimer = new FlxTimer().start(1 / 24, flickerProgress, 19); + } + + function flickerProgress(timer:FlxTimer):Void + { + if (flickerState == true) + { + whiteText.blend = BlendMode.ADD; + blurredText.blend = BlendMode.ADD; + blurredText.color = 0xFFFFFFFF; + whiteText.color = 0xFFFFFFFF; + whiteText.textField.filters = [ + new openfl.filters.GlowFilter(0xFFFFFF, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM), + // new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW) + ]; + } + else + { + blurredText.color = 0xFF00aadd; + whiteText.color = 0xFFDDDDDD; + whiteText.textField.filters = [ + new openfl.filters.GlowFilter(0xDDDDDD, 1, 5, 5, 210, BitmapFilterQuality.MEDIUM), + // new openfl.filters.BlurFilter(5, 5, BitmapFilterQuality.LOW) + ]; + } + flickerState = !flickerState; + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + } } diff --git a/source/funkin/ui/freeplay/DJBoyfriend.hx b/source/funkin/ui/freeplay/DJBoyfriend.hx index 5f1144fab..248526aaf 100644 --- a/source/funkin/ui/freeplay/DJBoyfriend.hx +++ b/source/funkin/ui/freeplay/DJBoyfriend.hx @@ -82,6 +82,8 @@ class DJBoyfriend extends FlxAtlasSprite return anims; } + var lowPumpLoopPoint:Int = 4; + public override function update(elapsed:Float):Void { super.update(elapsed); @@ -114,6 +116,14 @@ class DJBoyfriend extends FlxAtlasSprite case Confirm: if (getCurrentAnimation() != 'Boyfriend DJ confirm') playFlashAnimation('Boyfriend DJ confirm', false); timeSinceSpook = 0; + case PumpIntro: + if (getCurrentAnimation() != 'Boyfriend DJ fist pump') playFlashAnimation('Boyfriend DJ fist pump', false); + if (getCurrentAnimation() == 'Boyfriend DJ fist pump' && anim.curFrame >= 4) + { + anim.play("Boyfriend DJ fist pump", true, false, 0); + } + case FistPump: + case Spook: if (getCurrentAnimation() != 'bf dj afk') { @@ -174,6 +184,12 @@ class DJBoyfriend extends FlxAtlasSprite currentState = Idle; case "Boyfriend DJ confirm": + case "Boyfriend DJ fist pump": + currentState = Idle; + + case "Boyfriend DJ loss reaction 1": + currentState = Idle; + case "Boyfriend DJ watchin tv OG": var frame:Int = FlxG.random.bool(33) ? 112 : 166; @@ -275,6 +291,23 @@ class DJBoyfriend extends FlxAtlasSprite currentState = Confirm; } + public function fistPump():Void + { + currentState = PumpIntro; + } + + public function pumpFist():Void + { + currentState = FistPump; + anim.play("Boyfriend DJ fist pump", true, false, 4); + } + + public function pumpFistBad():Void + { + currentState = FistPump; + anim.play("Boyfriend DJ loss reaction 1", true, false, 4); + } + public inline function addOffset(name:String, x:Float = 0, y:Float = 0) { animOffsets[name] = [x, y]; @@ -331,6 +364,8 @@ enum DJBoyfriendState Intro; Idle; Confirm; + PumpIntro; + FistPump; Spook; TV; } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index c02199dcf..530f28c33 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1,5 +1,6 @@ package funkin.ui.freeplay; +import funkin.graphics.adobeanimate.FlxAtlasSprite; import flixel.addons.transition.FlxTransitionableState; import flixel.addons.ui.FlxInputText; import flixel.FlxCamera; @@ -10,6 +11,7 @@ import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.input.touch.FlxTouch; import flixel.math.FlxAngle; import flixel.math.FlxPoint; +import openfl.display.BlendMode; import flixel.system.debug.watch.Tracker.TrackerProfile; import flixel.text.FlxText; import flixel.tweens.FlxEase; @@ -38,6 +40,8 @@ import funkin.ui.transition.LoadingState; import funkin.ui.transition.StickerSubState; import funkin.util.MathUtil; import lime.utils.Assets; +import flixel.tweens.misc.ShakeTween; +import funkin.effects.IntervalShake; /** * Parameters used to initialize the FreeplayState. @@ -133,6 +137,29 @@ class FreeplayState extends MusicBeatSubState public static var rememberedDifficulty:Null = Constants.DEFAULT_DIFFICULTY; public static var rememberedSongId:Null = 'tutorial'; + var funnyCam:FunkinCamera; + var rankCamera:FunkinCamera; + var rankBg:FunkinSprite; + var rankVignette:FlxSprite; + + var backingTextYeah:FlxAtlasSprite; + var orangeBackShit:FunkinSprite; + var alsoOrangeLOL:FunkinSprite; + var pinkBack:FunkinSprite; + var confirmGlow:FlxSprite; + var confirmGlow2:FlxSprite; + var confirmTextGlow:FlxSprite; + + var moreWays:BGScrollingText; + var funnyScroll:BGScrollingText; + var txtNuts:BGScrollingText; + var funnyScroll2:BGScrollingText; + var moreWays2:BGScrollingText; + var funnyScroll3:BGScrollingText; + + var bgDad:FlxSprite; + var cardGlow:FlxSprite; + public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { currentCharacter = params?.character ?? Constants.DEFAULT_CHARACTER; @@ -211,17 +238,17 @@ class FreeplayState extends MusicBeatSubState trace(FlxG.camera.initialZoom); trace(FlxCamera.defaultZoom); - var pinkBack:FunkinSprite = FunkinSprite.create('freeplay/pinkBack'); + pinkBack = FunkinSprite.create('freeplay/pinkBack'); pinkBack.color = 0xFFFFD4E9; // sets it to pink! pinkBack.x -= pinkBack.width; FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut}); add(pinkBack); - var orangeBackShit:FunkinSprite = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFFEDA00); + orangeBackShit = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFFEDA00); add(orangeBackShit); - var alsoOrangeLOL:FunkinSprite = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFFFD400); + alsoOrangeLOL = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFFFD400); add(alsoOrangeLOL); exitMovers.set([pinkBack, orangeBackShit, alsoOrangeLOL], @@ -236,13 +263,30 @@ class FreeplayState extends MusicBeatSubState orangeBackShit.visible = false; alsoOrangeLOL.visible = false; + confirmTextGlow = new FlxSprite(-8, 115).loadGraphic(Paths.image('freeplay/glowingText')); + confirmTextGlow.blend = BlendMode.ADD; + confirmTextGlow.visible = false; + + confirmGlow = new FlxSprite(-30, 240).loadGraphic(Paths.image('freeplay/confirmGlow')); + confirmGlow.blend = BlendMode.ADD; + + confirmGlow2 = new FlxSprite(confirmGlow.x, confirmGlow.y).loadGraphic(Paths.image('freeplay/confirmGlow2')); + + confirmGlow.visible = false; + confirmGlow2.visible = false; + + add(confirmGlow2); + add(confirmGlow); + + add(confirmTextGlow); + var grpTxtScrolls:FlxGroup = new FlxGroup(); add(grpTxtScrolls); grpTxtScrolls.visible = false; FlxG.debugger.addTrackerProfile(new TrackerProfile(BGScrollingText, ['x', 'y', 'speed', 'size'])); - var moreWays:BGScrollingText = new BGScrollingText(0, 160, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); + moreWays = new BGScrollingText(0, 160, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); moreWays.funnyColor = 0xFFFFF383; moreWays.speed = 6.8; grpTxtScrolls.add(moreWays); @@ -253,7 +297,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.4, }); - var funnyScroll:BGScrollingText = new BGScrollingText(0, 220, 'BOYFRIEND', FlxG.width / 2, false, 60); + funnyScroll = new BGScrollingText(0, 220, 'BOYFRIEND', FlxG.width / 2, false, 60); funnyScroll.funnyColor = 0xFFFF9963; funnyScroll.speed = -3.8; grpTxtScrolls.add(funnyScroll); @@ -266,7 +310,7 @@ class FreeplayState extends MusicBeatSubState wait: 0 }); - var txtNuts:BGScrollingText = new BGScrollingText(0, 285, 'PROTECT YO NUTS', FlxG.width / 2, true, 43); + txtNuts = new BGScrollingText(0, 285, 'PROTECT YO NUTS', FlxG.width / 2, true, 43); txtNuts.speed = 3.5; grpTxtScrolls.add(txtNuts); exitMovers.set([txtNuts], @@ -275,7 +319,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.4, }); - var funnyScroll2:BGScrollingText = new BGScrollingText(0, 335, 'BOYFRIEND', FlxG.width / 2, false, 60); + funnyScroll2 = new BGScrollingText(0, 335, 'BOYFRIEND', FlxG.width / 2, false, 60); funnyScroll2.funnyColor = 0xFFFF9963; funnyScroll2.speed = -3.8; grpTxtScrolls.add(funnyScroll2); @@ -286,7 +330,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.5, }); - var moreWays2:BGScrollingText = new BGScrollingText(0, 397, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); + moreWays2 = new BGScrollingText(0, 397, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); moreWays2.funnyColor = 0xFFFFF383; moreWays2.speed = 6.8; grpTxtScrolls.add(moreWays2); @@ -297,7 +341,7 @@ class FreeplayState extends MusicBeatSubState speed: 0.4 }); - var funnyScroll3:BGScrollingText = new BGScrollingText(0, orangeBackShit.y + 10, 'BOYFRIEND', FlxG.width / 2, 60); + funnyScroll3 = new BGScrollingText(0, orangeBackShit.y + 10, 'BOYFRIEND', FlxG.width / 2, 60); funnyScroll3.funnyColor = 0xFFFEA400; funnyScroll3.speed = -3.8; grpTxtScrolls.add(funnyScroll3); @@ -308,6 +352,24 @@ class FreeplayState extends MusicBeatSubState speed: 0.3 }); + backingTextYeah = new FlxAtlasSprite(640, 370, Paths.animateAtlas("freeplay/backing-text-yeah"), + { + FrameRate: 24.0, + Reversed: false, + // ?OnComplete:Void -> Void, + ShowPivot: false, + Antialiasing: true, + ScrollFactor: new FlxPoint(1, 1), + }); + + add(backingTextYeah); + + cardGlow = new FlxSprite(-30, -30).loadGraphic(Paths.image('freeplay/cardGlow')); + cardGlow.blend = BlendMode.ADD; + cardGlow.visible = false; + + add(cardGlow); + dj = new DJBoyfriend(640, 366); exitMovers.set([dj], { @@ -320,7 +382,7 @@ class FreeplayState extends MusicBeatSubState add(dj); - var bgDad:FlxSprite = new FlxSprite(pinkBack.width * 0.75, 0).loadGraphic(Paths.image('freeplay/freeplayBGdad')); + bgDad = new FlxSprite(pinkBack.width * 0.75, 0).loadGraphic(Paths.image('freeplay/freeplayBGdad')); bgDad.setGraphicSize(0, FlxG.height); bgDad.updateHitbox(); bgDad.shader = new AngleMask(); @@ -337,10 +399,14 @@ class FreeplayState extends MusicBeatSubState }); add(bgDad); - FlxTween.tween(blackOverlayBullshitLOLXD, {x: pinkBack.width * 0.75}, 0.7, {ease: FlxEase.quintOut}); + FlxTween.tween(blackOverlayBullshitLOLXD, {x: pinkBack.width * 0.76}, 0.7, {ease: FlxEase.quintOut}); blackOverlayBullshitLOLXD.shader = bgDad.shader; + rankBg = new FunkinSprite(0, 0); + rankBg.makeSolidColor(FlxG.width, FlxG.height, 0xD3000000); + add(rankBg); + grpSongs = new FlxTypedGroup(); add(grpSongs); @@ -518,18 +584,35 @@ class FreeplayState extends MusicBeatSubState orangeBackShit.visible = true; alsoOrangeLOL.visible = true; grpTxtScrolls.visible = true; + + cardGlow.visible = true; + FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut}); }); generateSongList(null, false); // dedicated camera for the state so we don't need to fuk around with camera scrolls from the mainmenu / elsewhere - var funnyCam:FunkinCamera = new FunkinCamera('freeplayFunny', 0, 0, FlxG.width, FlxG.height); + funnyCam = new FunkinCamera('freeplayFunny', 0, 0, FlxG.width, FlxG.height); funnyCam.bgColor = FlxColor.TRANSPARENT; FlxG.cameras.add(funnyCam, false); + rankVignette = new FlxSprite(0, 0).loadGraphic(Paths.image('freeplay/rankVignette')); + rankVignette.scale.set(2, 2); + rankVignette.updateHitbox(); + rankVignette.blend = BlendMode.ADD; + // rankVignette.cameras = [rankCamera]; + add(rankVignette); + rankVignette.alpha = 0; + forEach(function(bs) { bs.cameras = [funnyCam]; }); + + rankCamera = new FunkinCamera('rankCamera', 0, 0, FlxG.width, FlxG.height); + rankCamera.bgColor = FlxColor.TRANSPARENT; + FlxG.cameras.add(rankCamera, false); + rankBg.cameras = [rankCamera]; + rankBg.alpha = 0; } var currentFilter:SongFilter = null; @@ -576,6 +659,7 @@ class FreeplayState extends MusicBeatSubState for (cap in grpCapsules.members) { + cap.songText.resetText(); cap.kill(); } @@ -593,9 +677,11 @@ class FreeplayState extends MusicBeatSubState }; randomCapsule.y = randomCapsule.intendedY(0) + 10; randomCapsule.targetPos.x = randomCapsule.x; - randomCapsule.alpha = 0.5; + randomCapsule.alpha = 0; randomCapsule.songText.visible = false; randomCapsule.favIcon.visible = false; + randomCapsule.ranking.visible = false; + randomCapsule.blurredRanking.visible = false; randomCapsule.initJumpIn(0, force); randomCapsule.hsvShader = hsvShader; grpCapsules.add(randomCapsule); @@ -618,8 +704,12 @@ class FreeplayState extends MusicBeatSubState funnyMenu.favIcon.visible = tempSongs[i].isFav; funnyMenu.hsvShader = hsvShader; + funnyMenu.newText.animation.curAnim.curFrame = 45 - ((i * 4) % 45); + funnyMenu.forcePosition(); + funnyMenu.checkClip(); + grpCapsules.add(funnyMenu); } @@ -673,6 +763,210 @@ class FreeplayState extends MusicBeatSubState return songsToFilter; } + function rankAnimStart() + { + dj.fistPump(); + // rankCamera.fade(FlxColor.BLACK, 0.5, true); + rankCamera.fade(0xFF000000, 0.5, true, null, true); + FlxG.sound.music.volume = 0; + rankBg.alpha = 1; + + originalPos.x = grpCapsules.members[curSelected].x; + originalPos.y = grpCapsules.members[curSelected].y; + + grpCapsules.members[curSelected].ranking.alpha = 0; + grpCapsules.members[curSelected].blurredRanking.alpha = 0; + + rankCamera.zoom = 1.85; + FlxTween.tween(rankCamera, {"zoom": 1.8}, 0.6, {ease: FlxEase.sineIn}); + + funnyCam.zoom = 1.15; + FlxTween.tween(funnyCam, {"zoom": 1.1}, 0.6, {ease: FlxEase.sineIn}); + + grpCapsules.members[curSelected].cameras = [rankCamera]; + grpCapsules.members[curSelected].targetPos.set((FlxG.width / 2) - (grpCapsules.members[curSelected].width / 2), + (FlxG.height / 2) - (grpCapsules.members[curSelected].height / 2)); + + new FlxTimer().start(0.5, _ -> { + grpCapsules.members[curSelected].doLerp = false; + rankDisplayNew(); + }); + } + + function rankDisplayNew() + { + grpCapsules.members[curSelected].ranking.alpha = 1; + grpCapsules.members[curSelected].blurredRanking.alpha = 1; + + grpCapsules.members[curSelected].ranking.scale.set(20, 20); + grpCapsules.members[curSelected].blurredRanking.scale.set(20, 20); + // var tempr:Int = FlxG.random.int(0, 4); + + // grpCapsules.members[curSelected].ranking.rank = tempr; + grpCapsules.members[curSelected].ranking.animation.play(grpCapsules.members[curSelected].ranking.animation.curAnim.name, true); + FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1); + + grpCapsules.members[curSelected].blurredRanking.animation.play(grpCapsules.members[curSelected].blurredRanking.animation.curAnim.name, true); + FlxTween.tween(grpCapsules.members[curSelected].blurredRanking, {"scale.x": 1, "scale.y": 1}, 0.1); + + new FlxTimer().start(0.1, _ -> { + trace(grpCapsules.members[curSelected].ranking.rank); + switch (grpCapsules.members[curSelected].tempr) + { + case 0: + FunkinSound.playOnce(Paths.sound('ranks/rankinbad')); + case 4: + FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); + case 5: + FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); + default: + FunkinSound.playOnce(Paths.sound('ranks/rankinnormal')); + } + rankCamera.zoom = 1.3; + // FlxTween.tween(rankCamera, {"zoom": 1.4}, 0.3, {ease: FlxEase.elasticOut}); + + FlxTween.tween(rankCamera, {"zoom": 1.5}, 0.3, {ease: FlxEase.backInOut}); + + grpCapsules.members[curSelected].x -= 10; + grpCapsules.members[curSelected].y -= 20; + + FlxTween.tween(funnyCam, {"zoom": 1.05}, 0.3, {ease: FlxEase.elasticOut}); + + grpCapsules.members[curSelected].capsule.angle = -3; + FlxTween.tween(grpCapsules.members[curSelected].capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + + IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0.1, 0, FlxEase.quadOut); + }); + + new FlxTimer().start(0.4, _ -> { + FlxTween.tween(funnyCam, {"zoom": 1}, 0.8, {ease: FlxEase.sineIn}); + FlxTween.tween(rankCamera, {"zoom": 1.2}, 0.8, {ease: FlxEase.backIn}); + // IntervalShake.shake(grpCapsules.members[curSelected], 0.8 + 0.5, 1 / 24, 0, 2, FlxEase.quadIn); + FlxTween.tween(grpCapsules.members[curSelected], {x: originalPos.x - 7, y: originalPos.y - 80}, 0.8 + 0.5, {ease: FlxEase.quartIn}); + }); + + new FlxTimer().start(0.6, _ -> { + rankAnimSlam(); + // IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0, 0.3, FlxEase.quartIn); + }); + } + + function rankAnimSlam() + { + // FlxTween.tween(rankCamera, {"zoom": 1.9}, 0.5, {ease: FlxEase.backOut}); + FlxTween.tween(rankBg, {alpha: 0}, 0.5, {ease: FlxEase.expoIn}); + + // FlxTween.tween(grpCapsules.members[curSelected], {angle: 5}, 0.5, {ease: FlxEase.backIn}); + + switch (grpCapsules.members[curSelected].tempr) + { + case 0: + FunkinSound.playOnce(Paths.sound('ranks/loss')); + case 1: + FunkinSound.playOnce(Paths.sound('ranks/good')); + case 2: + FunkinSound.playOnce(Paths.sound('ranks/great')); + case 3: + FunkinSound.playOnce(Paths.sound('ranks/excellent')); + case 4: + FunkinSound.playOnce(Paths.sound('ranks/perfect')); + case 5: + FunkinSound.playOnce(Paths.sound('ranks/perfect')); + default: + FunkinSound.playOnce(Paths.sound('ranks/loss')); + } + + FlxTween.tween(grpCapsules.members[curSelected], {"targetPos.x": originalPos.x, "targetPos.y": originalPos.y}, 0.5, {ease: FlxEase.expoOut}); + new FlxTimer().start(0.5, _ -> { + funnyCam.shake(0.0045, 0.35); + + if (grpCapsules.members[curSelected].tempr == 0) + { + dj.pumpFistBad(); + } + else + { + dj.pumpFist(); + } + + rankCamera.zoom = 0.8; + funnyCam.zoom = 0.8; + FlxTween.tween(rankCamera, {"zoom": 1}, 1, {ease: FlxEase.elasticOut}); + FlxTween.tween(funnyCam, {"zoom": 1}, 0.8, {ease: FlxEase.elasticOut}); + + for (index => capsule in grpCapsules.members) + { + var distFromSelected:Float = Math.abs(index - curSelected) - 1; + + if (distFromSelected < 5) + { + if (index == curSelected) + { + FlxTween.cancelTweensOf(capsule); + // capsule.targetPos.x += 50; + capsule.fadeAnim(); + + rankVignette.color = capsule.getTrailColor(); + rankVignette.alpha = 1; + FlxTween.tween(rankVignette, {alpha: 0}, 0.6, {ease: FlxEase.expoOut}); + + capsule.doLerp = false; + capsule.setPosition(originalPos.x, originalPos.y); + IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12, 0, FlxEase.quadOut, function(_) { + capsule.doLerp = true; + capsule.cameras = [funnyCam]; + }, null); + + // FlxTween.tween(capsule, {"targetPos.x": capsule.targetPos.x - 50}, 0.6, + // { + // ease: FlxEase.backInOut, + // onComplete: function(_) { + // capsule.cameras = [funnyCam]; + // } + // }); + FlxTween.tween(capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + } + if (index > curSelected) + { + // capsule.color = FlxColor.RED; + new FlxTimer().start(distFromSelected / 20, _ -> { + capsule.doLerp = false; + + capsule.capsule.angle = FlxG.random.float(-10 + (distFromSelected * 2), 10 - (distFromSelected * 2)); + FlxTween.tween(capsule.capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + + IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12 / (distFromSelected + 1), 0, FlxEase.quadOut, function(_) { + capsule.doLerp = true; + }); + }); + } + + if (index < curSelected) + { + // capsule.color = FlxColor.BLUE; + new FlxTimer().start(distFromSelected / 20, _ -> { + capsule.doLerp = false; + + capsule.capsule.angle = FlxG.random.float(-10 + (distFromSelected * 2), 10 - (distFromSelected * 2)); + FlxTween.tween(capsule.capsule, {angle: 0}, 0.5, {ease: FlxEase.backOut}); + + IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12 / (distFromSelected + 1), 0, FlxEase.quadOut, function(_) { + capsule.doLerp = true; + }); + }); + } + } + + index += 1; + } + }); + + new FlxTimer().start(2, _ -> { + // dj.fistPump(); + FlxG.sound.music.fadeIn(4.0, 0.0, 1.0); + }); + } + var touchY:Float = 0; var touchX:Float = 0; var dxTouch:Float = 0; @@ -689,10 +983,48 @@ class FreeplayState extends MusicBeatSubState var busy:Bool = false; // Set to true once the user has pressed enter to select a song. + var originalPos:FlxPoint = new FlxPoint(); + override function update(elapsed:Float):Void { super.update(elapsed); + if (FlxG.keys.justPressed.T) + { + rankAnimStart(); + } + + if (FlxG.keys.justPressed.H) + { + rankDisplayNew(); + } + + if (FlxG.keys.justPressed.G) + { + rankAnimSlam(); + } + + if (FlxG.keys.justPressed.I) + { + confirmTextGlow.y -= 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.J) + { + confirmTextGlow.x -= 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.L) + { + confirmTextGlow.x += 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.K) + { + confirmTextGlow.y += 1; + trace(confirmTextGlow.x, confirmTextGlow.y); + } + if (FlxG.keys.justPressed.F) { var targetSong = grpCapsules.members[curSelected]?.songData; @@ -1153,6 +1485,42 @@ class FreeplayState extends MusicBeatSubState FunkinSound.playOnce(Paths.sound('confirmMenu')); dj.confirm(); + grpCapsules.members[curSelected].songText.flickerText(); + + // FlxTween.color(bgDad, 0.33, 0xFFFFFFFF, 0xFF555555, {ease: FlxEase.quadOut}); + FlxTween.color(pinkBack, 0.33, 0xFFFFD0D5, 0xFF171831, {ease: FlxEase.quadOut}); + orangeBackShit.visible = false; + alsoOrangeLOL.visible = false; + + confirmGlow.visible = true; + confirmGlow2.visible = true; + + backingTextYeah.anim.play("BF back card confirm raw", false, false, 0); + confirmGlow2.alpha = 0; + confirmGlow.alpha = 0; + + FlxTween.tween(confirmGlow2, {alpha: 0.5}, 0.33, + { + ease: FlxEase.quadOut, + onComplete: function(_) { + confirmGlow2.alpha = 0.6; + confirmGlow.alpha = 1; + confirmTextGlow.visible = true; + confirmTextGlow.alpha = 1; + FlxTween.tween(confirmTextGlow, {alpha: 0.4}, 0.5); + FlxTween.tween(confirmGlow, {alpha: 0}, 0.5); + } + }); + + // confirmGlow + + moreWays.visible = false; + funnyScroll.visible = false; + txtNuts.visible = false; + funnyScroll2.visible = false; + moreWays2.visible = false; + funnyScroll3.visible = false; + new FlxTimer().start(1, function(tmr:FlxTimer) { Paths.setCurrentLevel(cap.songData.levelId); LoadingState.loadPlayState( @@ -1391,6 +1759,7 @@ class FreeplaySongData public var songName(default, null):String = ''; public var songCharacter(default, null):String = ''; + public var songStartingBpm(default, null):Float = 0; public var difficultyRating(default, null):Int = 0; public var albumId(default, null):Null = null; @@ -1445,6 +1814,7 @@ class FreeplaySongData var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, variations); if (songDifficulty == null) return; + this.songStartingBpm = songDifficulty.getStartingBPM(); this.songName = songDifficulty.songName; this.songCharacter = songDifficulty.characters.opponent; this.difficultyRating = songDifficulty.difficultyRating; diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index cf9b52482..536a9cfe6 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -14,6 +14,13 @@ import flixel.text.FlxText; import flixel.util.FlxTimer; import funkin.util.MathUtil; import funkin.graphics.shaders.Grayscale; +import funkin.graphics.shaders.GaussianBlurShader; +import openfl.display.BlendMode; +import funkin.graphics.FunkinSprite; +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import flixel.addons.effects.FlxTrail; +import flixel.util.FlxColor; class SongMenuItem extends FlxSpriteGroup { @@ -31,9 +38,10 @@ class SongMenuItem extends FlxSpriteGroup public var songText:CapsuleText; public var favIcon:FlxSprite; - public var ranking:FlxSprite; + public var ranking:FreeplayRank; + public var blurredRanking:FreeplayRank; - var ranks:Array = ["fail", "average", "great", "excellent", "perfect"]; + var ranks:Array = ["fail", "average", "great", "excellent", "perfect", "perfectsick"]; public var targetPos:FlxPoint = new FlxPoint(); public var doLerp:Bool = false; @@ -47,6 +55,22 @@ class SongMenuItem extends FlxSpriteGroup public var hsvShader(default, set):HSVShader; // var diffRatingSprite:FlxSprite; + public var bpmText:FlxSprite; + public var difficultyText:FlxSprite; + public var weekType:FlxSprite; + + public var newText:FlxSprite; + + // public var weekType:FlxSprite; + public var bigNumbers:Array = []; + + public var smallNumbers:Array = []; + + public var weekNumbers:Array = []; + + var impactThing:FunkinSprite; + + public var tempr:Int; public function new(x:Float, y:Float) { @@ -59,12 +83,64 @@ class SongMenuItem extends FlxSpriteGroup // capsule.animation add(capsule); + bpmText = new FlxSprite(144, 87).loadGraphic(Paths.image('freeplay/freeplayCapsule/bpmtext')); + bpmText.setGraphicSize(Std.int(bpmText.width * 0.9)); + add(bpmText); + + difficultyText = new FlxSprite(414, 87).loadGraphic(Paths.image('freeplay/freeplayCapsule/difficultytext')); + difficultyText.setGraphicSize(Std.int(difficultyText.width * 0.9)); + add(difficultyText); + + weekType = new FlxSprite(291, 87); + weekType.frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/weektypes'); + + weekType.animation.addByPrefix('WEEK', 'WEEK text instance 1', 24, false); + weekType.animation.addByPrefix('WEEKEND', 'WEEKEND text instance 1', 24, false); + + weekType.setGraphicSize(Std.int(weekType.width * 0.9)); + add(weekType); + + newText = new FlxSprite(454, 9); + newText.frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/new'); + newText.animation.addByPrefix('newAnim', 'NEW notif', 24, true); + newText.animation.play('newAnim', true); + newText.setGraphicSize(Std.int(newText.width * 0.9)); + + newText.visible = false; + + add(newText); + + // var debugNumber2:CapsuleNumber = new CapsuleNumber(0, 0, true, 2); + // add(debugNumber2); + + for (i in 0...2) + { + var bigNumber:CapsuleNumber = new CapsuleNumber(466 + (i * 30), 32, true, 0); + add(bigNumber); + + bigNumbers.push(bigNumber); + } + + for (i in 0...3) + { + var smallNumber:CapsuleNumber = new CapsuleNumber(185 + (i * 11), 88.5, false, 0); + add(smallNumber); + + smallNumbers.push(smallNumber); + } + // doesn't get added, simply is here to help with visibility of things for the pop in! grpHide = new FlxGroup(); var rank:String = FlxG.random.getObject(ranks); - ranking = new FlxSprite(capsule.width * 0.84, 30); + tempr = FlxG.random.int(0, 5); + ranking = new FreeplayRank(420, 41, tempr); + add(ranking); + + blurredRanking = new FreeplayRank(ranking.x, ranking.y, tempr); + blurredRanking.shader = new GaussianBlurShader(1); + add(blurredRanking); // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); // ranking.scale.x = ranking.scale.y = realScaled; // ranking.alpha = 0.75; @@ -73,11 +149,11 @@ class SongMenuItem extends FlxSpriteGroup // add(ranking); // grpHide.add(ranking); - switch (rank) - { - case 'perfect': - ranking.x -= 10; - } + // switch (rank) + // { + // case 'perfect': + // ranking.x -= 10; + // } grayscaleShader = new Grayscale(1); @@ -93,7 +169,7 @@ class SongMenuItem extends FlxSpriteGroup grpHide.add(songText); // TODO: Use value from metadata instead of random. - updateDifficultyRating(FlxG.random.int(0, 15)); + updateDifficultyRating(FlxG.random.int(0, 20)); pixelIcon = new FlxSprite(160, 35); @@ -103,21 +179,216 @@ class SongMenuItem extends FlxSpriteGroup add(pixelIcon); grpHide.add(pixelIcon); - favIcon = new FlxSprite(400, 40); + favIcon = new FlxSprite(380, 40); favIcon.frames = Paths.getSparrowAtlas('freeplay/favHeart'); favIcon.animation.addByPrefix('fav', 'favorite heart', 24, false); favIcon.animation.play('fav'); favIcon.setGraphicSize(50, 50); favIcon.visible = false; + favIcon.blend = BlendMode.ADD; add(favIcon); - // grpHide.add(favIcon); + + var weekNumber:CapsuleNumber = new CapsuleNumber(355, 88.5, false, 0); + add(weekNumber); + + weekNumbers.push(weekNumber); setVisibleGrp(false); } + // no way to grab weeks rn, so this needs to be done :/ + // negative values mean weekends + function checkWeek(name:String):Void + { + // trace(name); + var weekNum:Int = 0; + switch (name) + { + case 'bopeebo' | 'fresh' | 'dadbattle': + weekNum = 1; + case 'spookeez' | 'south' | 'monster': + weekNum = 2; + case 'pico' | 'philly-nice' | 'blammed': + weekNum = 3; + case "satin-panties" | 'high' | 'milf': + weekNum = 4; + case "cocoa" | 'eggnog' | 'winter-horrorland': + weekNum = 5; + case 'senpai' | 'roses' | 'thorns': + weekNum = 6; + case 'ugh' | 'guns' | 'stress': + weekNum = 7; + case 'darnell' | 'lit-up' | '2hot' | 'blazin': + weekNum = -1; + default: + weekNum = 0; + } + + weekNumbers[0].digit = Std.int(Math.abs(weekNum)); + + if (weekNum == 0) + { + weekType.visible = false; + weekNumbers[0].visible = false; + } + else + { + weekType.visible = true; + weekNumbers[0].visible = true; + } + if (weekNum > 0) + { + weekType.animation.play('WEEK', true); + } + else + { + weekType.animation.play('WEEKEND', true); + weekNumbers[0].offset.x -= 35; + } + } + + // 255, 27 normal + // 220, 27 favourited + public function checkClip():Void + { + var clipSize:Int = 290; + var clipType:Int = 0; + + if (ranking.visible == true) clipType += 1; + if (favIcon.visible == true) clipType += 1; + switch (clipType) + { + case 2: + clipSize = 220; + case 1: + clipSize = 255; + } + songText.clipWidth = clipSize; + } + + function updateBPM(newBPM:Int):Void + { + trace(newBPM); + + var shiftX:Float = 191; + var tempShift:Float = 0; + + if (Math.floor(newBPM / 100) == 1) + { + shiftX = 186; + } + + for (i in 0...smallNumbers.length) + { + smallNumbers[i].x = this.x + (shiftX + (i * 11)); + switch (i) + { + case 0: + if (newBPM < 100) + { + smallNumbers[i].digit = 0; + } + else + { + smallNumbers[i].digit = Math.floor(newBPM / 100) % 10; + } + + case 1: + if (newBPM < 10) + { + smallNumbers[i].digit = 0; + } + else + { + smallNumbers[i].digit = Math.floor(newBPM / 10) % 10; + + if (Math.floor(newBPM / 10) % 10 == 1) tempShift = -4; + } + case 2: + smallNumbers[i].digit = newBPM % 10; + default: + trace('why the fuck is this being called'); + } + smallNumbers[i].x += tempShift; + } + // diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}')); + // diffRatingSprite.visible = false; + } + + var evilTrail:FlxTrail; + + public function fadeAnim() + { + impactThing = new FunkinSprite(0, 0); + impactThing.frames = capsule.frames; + impactThing.frame = capsule.frame; + impactThing.updateHitbox(); + // impactThing.x = capsule.x; + // impactThing.y = capsule.y; + // picoFade.stamp(this, 0, 0); + impactThing.alpha = 0; + impactThing.zIndex = capsule.zIndex - 3; + add(impactThing); + FlxTween.tween(impactThing.scale, {x: 2.5, y: 2.5}, 0.5); + // FlxTween.tween(impactThing, {alpha: 0}, 0.5); + + evilTrail = new FlxTrail(impactThing, null, 15, 2, 0.01, 0.069); + evilTrail.blend = BlendMode.ADD; + evilTrail.zIndex = capsule.zIndex - 5; + FlxTween.tween(evilTrail, {alpha: 0}, 0.6, + { + ease: FlxEase.quadOut, + onComplete: function(_) { + remove(evilTrail); + } + }); + add(evilTrail); + + switch (tempr) + { + case 0: + evilTrail.color = 0xFF6044FF; + case 1: + evilTrail.color = 0xFFEF8764; + case 2: + evilTrail.color = 0xFFEAF6FF; + case 3: + evilTrail.color = 0xFFFDCB42; + case 4: + evilTrail.color = 0xFFFF58B4; + case 5: + evilTrail.color = 0xFFFFB619; + } + } + + public function getTrailColor():FlxColor + { + return evilTrail.color; + } + function updateDifficultyRating(newRating:Int):Void { var ratingPadded:String = newRating < 10 ? '0$newRating' : '$newRating'; + + for (i in 0...bigNumbers.length) + { + switch (i) + { + case 0: + if (newRating > 10) + { + bigNumbers[i].digit = 0; + } + else + { + bigNumbers[i].digit = Math.floor(newRating / 10); + } + case 1: + bigNumbers[i].digit = newRating % 10; + default: + trace('why the fuck is this being called'); + } + } // diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}')); // diffRatingSprite.visible = false; } @@ -168,9 +439,12 @@ class SongMenuItem extends FlxSpriteGroup songText.text = songData?.songName ?? 'Random'; // Update capsule character. if (songData?.songCharacter != null) setCharacter(songData.songCharacter); + updateBPM(Std.int(songData?.songStartingBpm) ?? 0); updateDifficultyRating(songData?.difficultyRating ?? 0); // Update opacity, offsets, etc. updateSelected(); + + checkWeek(songData?.songId); } /** @@ -289,6 +563,28 @@ class SongMenuItem extends FlxSpriteGroup override function update(elapsed:Float):Void { + if (impactThing != null) impactThing.angle = capsule.angle; + + // if (FlxG.keys.justPressed.I) + // { + // newText.y -= 1; + // trace(this.x - newText.x, this.y - newText.y); + // } + // if (FlxG.keys.justPressed.J) + // { + // newText.x -= 1; + // trace(this.x - newText.x, this.y - newText.y); + // } + // if (FlxG.keys.justPressed.L) + // { + // newText.x += 1; + // trace(this.x - newText.x, this.y - newText.y); + // } + // if (FlxG.keys.justPressed.K) + // { + // newText.y += 1; + // trace(this.x - newText.x, this.y - newText.y); + // } if (doJumpIn) { frameInTicker += elapsed; @@ -358,5 +654,137 @@ class SongMenuItem extends FlxSpriteGroup capsule.animation.play(this.selected ? "selected" : "unselected"); ranking.alpha = this.selected ? 1 : 0.7; ranking.color = this.selected ? 0xFFFFFFFF : 0xFFAAAAAA; + + if (selected) + { + if (songText.tooLong == true) songText.initMove(); + } + else + { + if (songText.tooLong == true) songText.resetText(); + } + } +} + +class FreeplayRank extends FlxSprite +{ + public var rank(default, set):Int = 0; + + var numToRank:Array = ["LOSS", "GOOD", "GREAT", "EXCELLENT", "PERFECT", "PERFECTSICK"]; + + function set_rank(val):Int + { + animation.play(numToRank[val], true, false); + + centerOffsets(false); + + switch (val) + { + case 0: + // offset.x -= 1; + case 1: + // offset.x -= 1; + offset.y -= 8; + case 2: + // offset.x -= 1; + offset.y -= 8; + case 3: + // offset.y += 5; + case 4: + // offset.y += 5; + default: + centerOffsets(false); + } + updateHitbox(); + return val; + } + + public var baseY:Float = 0; + public var baseX:Float = 0; + + public function new(x:Float, y:Float, ?initRank:Int = 0) + { + super(x, y); + + frames = Paths.getSparrowAtlas('freeplay/rankbadges'); + + animation.addByPrefix('PERFECT', 'PERFECT rank0', 24, false); + animation.addByPrefix('EXCELLENT', 'EXCELLENT rank0', 24, false); + animation.addByPrefix('GOOD', 'GOOD rank0', 24, false); + animation.addByPrefix('PERFECTSICK', 'PERFECT rank GOLD', 24, false); + animation.addByPrefix('GREAT', 'GREAT rank0', 24, false); + animation.addByPrefix('LOSS', 'LOSS rank0', 24, false); + + blend = BlendMode.ADD; + + this.rank = initRank; + + animation.play(numToRank[initRank], true); + + // setGraphicSize(Std.int(width * 0.9)); + scale.set(0.9, 0.9); + updateHitbox(); + } +} + +class CapsuleNumber extends FlxSprite +{ + public var digit(default, set):Int = 0; + + function set_digit(val):Int + { + animation.play(numToString[val], true, false, 0); + + centerOffsets(false); + + switch (val) + { + case 1: + offset.x -= 4; + case 3: + offset.x -= 1; + + case 6: + + case 4: + // offset.y += 5; + case 9: + // offset.y += 5; + default: + centerOffsets(false); + } + return val; + } + + public var baseY:Float = 0; + public var baseX:Float = 0; + + var numToString:Array = ["ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"]; + + public function new(x:Float, y:Float, big:Bool = false, ?initDigit:Int = 0) + { + super(x, y); + + if (big) + { + frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/bignumbers'); + } + else + { + frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule/smallnumbers'); + } + + for (i in 0...10) + { + var stringNum:String = numToString[i]; + animation.addByPrefix(stringNum, '$stringNum', 24, false); + } + + this.digit = initDigit; + + animation.play(numToString[initDigit], true); + + setGraphicSize(Std.int(width * 0.9)); + updateHitbox(); } }