diff --git a/art b/art index e2663c1cb..0bb988c49 160000 --- a/art +++ b/art @@ -1 +1 @@ -Subproject commit e2663c1cbe029f04a98500735943f0b9465548bf +Subproject commit 0bb988c49788fd25a230b56dd9e4448838bc79c9 diff --git a/assets b/assets index a00554b4c..335fac6af 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit a00554b4c78d3d1da18436bc285ccbe1f4ea98f2 +Subproject commit 335fac6af6b3362b1de5f233865486eaf9fbae11 diff --git a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx index fefb224eb..f245afec7 100644 --- a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx +++ b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx @@ -95,7 +95,7 @@ class FlxAtlasSprite extends FlxAnimate */ public function hasAnimation(id:String):Bool { - return getLabelIndex(id) != -1; + return getLabelIndex(id) != -1 || anim.symbolDictionary.exists(id); } /** @@ -112,6 +112,8 @@ class FlxAtlasSprite extends FlxAnimate var looping:Bool = false; + public var ignoreExclusionPref:Array = []; + /** * Plays an animation. * @param id A string ID of the animation to play. @@ -124,7 +126,25 @@ class FlxAtlasSprite extends FlxAnimate public function playAnimation(id:String, restart:Bool = false, ignoreOther:Bool = false, loop:Bool = false, startFrame:Int = 0):Void { // Skip if not allowed to play animations. - if ((!canPlayOtherAnims && !ignoreOther)) return; + if ((!canPlayOtherAnims)) + { + if (this.currentAnimation == id && restart) {} + else if (ignoreExclusionPref != null && ignoreExclusionPref.length > 0) + { + var detected:Bool = false; + for (entry in ignoreExclusionPref) + { + if (StringTools.startsWith(id, entry)) + { + detected = true; + break; + } + } + if (!detected) return; + } + else + return; + } if (anim == null) return; @@ -132,38 +152,29 @@ class FlxAtlasSprite extends FlxAnimate if (this.currentAnimation == id && !restart) { - if (anim.isPlaying) - { - // Skip if animation is already playing. - return; - } - else + if (!anim.isPlaying) { + if (fr != null) anim.curFrame = fr.index + startFrame; + else + anim.curFrame = startFrame; + // Resume animation if it's paused. - anim.play('', restart, false, startFrame); + anim.resume(); } + + return; } - else + else if (!hasAnimation(id)) { // Skip if the animation doesn't exist - if (!hasAnimation(id)) - { - trace('Animation ' + id + ' not found'); - return; - } + trace('Animation ' + id + ' not found'); + return; } + this.currentAnimation = id; anim.onComplete.removeAll(); anim.onComplete.add(function() { - if (loop) - { - this.anim.play(id, restart, false, startFrame); - this.currentAnimation = id; - } - else - { - onAnimationComplete.dispatch(id); - } + _onAnimationComplete(); }); looping = loop; @@ -177,16 +188,17 @@ class FlxAtlasSprite extends FlxAnimate if (this.anim.symbolDictionary.exists(id) || (this.anim.getByName(id) != null)) { this.anim.play(id, restart, false, startFrame); + + if (id == "Boyfriend DJ fist pump" || startFrame == 4) trace("PUMP COMMAND: " + anim.curFrame); + fr = null; } // Only call goToFrameLabel if there is a frame label with that name. This prevents annoying warnings! if (getFrameLabelNames().indexOf(id) != -1) { goToFrameLabel(id); fr = anim.getFrameLabel(id); + anim.curFrame += startFrame; } - - anim.curFrame += startFrame; - this.currentAnimation = id; } override public function update(elapsed:Float) @@ -284,12 +296,13 @@ class FlxAtlasSprite extends FlxAnimate { anim.pause(); _onAnimationComplete(); + if (looping) { anim.curFrame = (fr != null) ? fr.index : 0; anim.resume(); } - else + else if (fr != null && anim.curFrame != anim.length - 1) { anim.curFrame--; } diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index e7087e340..e0ac3579d 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -194,6 +194,7 @@ class ResultState extends MusicBeatSubState { // Animation is not looped. animation.onAnimationComplete.add((_name:String) -> { + trace("AHAHAH 2"); if (animation != null) { animation.anim.pause(); @@ -203,9 +204,10 @@ class ResultState extends MusicBeatSubState else if (animData.loopFrameLabel != null) { animation.onAnimationComplete.add((_name:String) -> { + trace("AHAHAH 2"); if (animation != null) { - animation.playAnimation(animData.loopFrameLabel ?? ''); // unpauses this anim, since it's on PlayOnce! + animation.playAnimation(animData.loopFrameLabel ?? '', true, false, true); // unpauses this anim, since it's on PlayOnce! } }); } @@ -214,6 +216,7 @@ class ResultState extends MusicBeatSubState animation.onAnimationComplete.add((_name:String) -> { if (animation != null) { + trace("AHAHAH"); animation.anim.curFrame = animData.loopFrame ?? 0; animation.anim.play(); // unpauses this anim, since it's on PlayOnce! } diff --git a/source/funkin/play/character/AnimateAtlasCharacter.hx b/source/funkin/play/character/AnimateAtlasCharacter.hx index f432d08a0..b78aed983 100644 --- a/source/funkin/play/character/AnimateAtlasCharacter.hx +++ b/source/funkin/play/character/AnimateAtlasCharacter.hx @@ -166,6 +166,8 @@ class AnimateAtlasCharacter extends BaseCharacter this.mainSprite = sprite; + mainSprite.ignoreExclusionPref = ["sing"]; + // This forces the atlas to recalcuate its width and height this.mainSprite.alpha = 0.0001; this.mainSprite.draw(); diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index bce7f0d98..365c8d112 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -151,6 +151,8 @@ class BaseCharacter extends Bopper super(CharacterDataParser.DEFAULT_DANCEEVERY); this.characterId = id; + ignoreExclusionPref = ["sing"]; + _data = CharacterDataParser.fetchCharacterData(this.characterId); if (_data == null) { diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx index 96a217d31..721a60517 100644 --- a/source/funkin/play/stage/Bopper.hx +++ b/source/funkin/play/stage/Bopper.hx @@ -260,6 +260,8 @@ class Bopper extends StageProp implements IPlayStateScriptedClass public var canPlayOtherAnims:Bool = true; + public var ignoreExclusionPref:Array = []; + /** * @param name The name of the animation to play. * @param restart Whether to restart the animation if it is already playing. @@ -268,7 +270,26 @@ class Bopper extends StageProp implements IPlayStateScriptedClass */ public function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reversed:Bool = false):Void { - if (!canPlayOtherAnims && !ignoreOther) return; + if ((!canPlayOtherAnims)) + { + var id = name; + if (getCurrentAnimation() == id && restart) {} + else if (ignoreExclusionPref != null && ignoreExclusionPref.length > 0) + { + var detected:Bool = false; + for (entry in ignoreExclusionPref) + { + if (StringTools.startsWith(id, entry)) + { + detected = true; + break; + } + } + if (!detected) return; + } + else + return; + } var correctName = correctAnimationName(name); if (correctName == null) return; diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 80b05e5ac..1fa283b26 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -125,6 +125,7 @@ class Save { // Default to having seen the default character. charactersSeen: ["bf"], + oldChar: false }, optionsChartEditor: @@ -406,6 +407,18 @@ class Save return data.unlocks.charactersSeen; } + public var oldChar(get, set):Bool; + + function get_oldChar():Bool + { + return data.unlocks.oldChar; + } + + function set_oldChar(value:Bool):Bool + { + return data.unlocks.oldChar = value; + } + /** * When we've seen a character unlock, add it to the list of characters seen. * @param character @@ -1027,6 +1040,12 @@ typedef SaveDataUnlocks = * add it to this list so that we don't show it again. */ var charactersSeen:Array; + + /** + * This is a conditional when the player enters the character state + * For the first time ever + */ + var oldChar:Bool; } /** diff --git a/source/funkin/ui/charSelect/CharSelectPlayer.hx b/source/funkin/ui/charSelect/CharSelectPlayer.hx index 710bdd45a..b6319f16d 100644 --- a/source/funkin/ui/charSelect/CharSelectPlayer.hx +++ b/source/funkin/ui/charSelect/CharSelectPlayer.hx @@ -27,7 +27,7 @@ class CharSelectPlayer extends FlxAtlasSprite implements IBPMSyncedScriptedClass case "deselect": playAnimation("deselect loop start", true, false, true); - case "slidein idle point", "cannot select", "unlock": + case "slidein idle point", "cannot select Label", "unlock": playAnimation("idle", true, false, false); case "idle": trace('Waiting for onBeatHit'); diff --git a/source/funkin/ui/charSelect/CharSelectSubState.hx b/source/funkin/ui/charSelect/CharSelectSubState.hx index aa207c865..bd55bfdd9 100644 --- a/source/funkin/ui/charSelect/CharSelectSubState.hx +++ b/source/funkin/ui/charSelect/CharSelectSubState.hx @@ -35,55 +35,44 @@ import openfl.filters.ShaderFilter; import funkin.util.FramesJSFLParser; import funkin.util.FramesJSFLParser.FramesJSFLInfo; import funkin.util.FramesJSFLParser.FramesJSFLFrame; +import funkin.graphics.FunkinSprite; class CharSelectSubState extends MusicBeatSubState { var cursor:FlxSprite; + var cursorBlue:FlxSprite; var cursorDarkBlue:FlxSprite; - var grpCursors:FlxTypedGroup; - var cursorConfirmed:FlxSprite; var cursorDenied:FlxSprite; - var cursorX:Int = 0; var cursorY:Int = 0; - var cursorFactor:Float = 110; var cursorOffsetX:Float = -16; var cursorOffsetY:Float = -48; - var cursorLocIntended:FlxPoint = new FlxPoint(0, 0); var lerpAmnt:Float = 0.95; - var tmrFrames:Int = 60; - var currentStage:Stage; - var playerChill:CharSelectPlayer; var playerChillOut:CharSelectPlayer; var gfChill:CharSelectGF; var gfChillOut:CharSelectGF; - var barthing:FlxAtlasSprite; var dipshitBacking:FlxSprite; var chooseDipshit:FlxSprite; var dipshitBlur:FlxSprite; var transitionGradient:FlxSprite; - var curChar(default, set):String = "pico"; var nametag:Nametag; var camFollow:FlxObject; var autoFollow:Bool = false; - var availableChars:Map = new Map(); var pressedSelect:Bool = false; - var selectTimer:FlxTimer = new FlxTimer(); var selectSound:FunkinSound; var unlockSound:FunkinSound; - var charSelectCam:FunkinCamera; var selectedBizz:Array = [ @@ -92,6 +81,7 @@ class CharSelectSubState extends MusicBeatSubState ]; var bopInfo:FramesJSFLInfo; + var blackScreen:FunkinSprite; public function new() { @@ -125,11 +115,6 @@ class CharSelectSubState extends MusicBeatSubState override public function create():Void { - openSubState(new IntroSubState()); - subStateClosed.addOnce((_) -> { - camera.flash(); - checkNewChar(); - }); super.create(); bopInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/iconBopInfo/iconBopInfo.txt")); @@ -365,6 +350,20 @@ class CharSelectSubState extends MusicBeatSubState FlxG.camera.follow(camFollow, LOCKON, 0.01); } }); + + var blackScreen = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, 0xFF000000); + blackScreen.x = -(FlxG.width * 0.5); + blackScreen.y = -(FlxG.height * 0.5); + add(blackScreen); + + openSubState(new IntroSubState()); + subStateClosed.addOnce((_) -> { + remove(blackScreen); + if (!Save.instance.oldChar) camera.flash(); + checkNewChar(); + + Save.instance.oldChar = true; + }); } function checkNewChar():Void @@ -396,7 +395,6 @@ class CharSelectSubState extends MusicBeatSubState var grpIcons:FlxSpriteGroup; var grpXSpread(default, set):Float = 107; var grpYSpread(default, set):Float = 127; - var nonLocks = []; function initLocks():Void @@ -426,9 +424,9 @@ class CharSelectSubState extends MusicBeatSubState var temp:Lock = new Lock(0, 0, i); temp.ID = 1; - temp.onAnimationComplete.add(function(anim) { - if (anim == "unlock") playerChill.playAnimation("unlock", true); - }); + // temp.onAnimationComplete.add(function(anim) { + // if (anim == "unlock") playerChill.playAnimation("unlock", true); + // }); grpIcons.add(temp); } @@ -443,7 +441,7 @@ class CharSelectSubState extends MusicBeatSubState { var index = nonLocks[0]; - // pressedSelect = true; + pressedSelect = true; var copy = 3; @@ -478,7 +476,7 @@ class CharSelectSubState extends MusicBeatSubState syncLock = lock; - // sync = true; + sync = true; lock.onAnimationComplete.addOnce(function(_) { syncLock = null; @@ -561,9 +559,7 @@ class CharSelectSubState extends MusicBeatSubState } var sync:Bool = false; - var syncLock:Lock = null; - var audioBizz:Float = 0; function syncAudio(elapsed:Float):Void @@ -580,8 +576,6 @@ class CharSelectSubState extends MusicBeatSubState playerChillOut.anim._tick = 0; if (syncLock != null) syncLock.anim._tick = 0; - trace(unlockSound.time); - if ((unlockSound.time - audioBizz) >= (delay * 1000)) { if (syncLock != null) syncLock.anim._tick = delay; @@ -738,7 +732,7 @@ class CharSelectSubState extends MusicBeatSubState { curChar = availableChars.get(getCurrentSelected()); - if (controls.ACCEPT) + if (!pressedSelect && controls.ACCEPT) { cursorConfirmed.visible = true; cursorConfirmed.x = cursor.x - 2; @@ -775,6 +769,7 @@ class CharSelectSubState extends MusicBeatSubState FlxTween.tween(FlxG.sound.music, {pitch: 1.0, volume: 1.0}, 1, {ease: FlxEase.quartInOut}); playerChill.playAnimation("deselect"); gfChill.playAnimation("deselect"); + pressedSelect = false; FlxTween.tween(FlxG.sound.music, {pitch: 1.0}, 1, { ease: FlxEase.quartInOut, @@ -783,7 +778,6 @@ class CharSelectSubState extends MusicBeatSubState gfChill.playAnimation("idle", true, false, true); } }); - pressedSelect = false; selectTimer.cancel(); } } @@ -797,7 +791,7 @@ class CharSelectSubState extends MusicBeatSubState cursorDenied.x = cursor.x - 2; cursorDenied.y = cursor.y - 4; - playerChill.playAnimation("cannot select", true); + playerChill.playAnimation("cannot select Label", true); cursorDenied.animation.play("idle", true); cursorDenied.animation.finishCallback = (_) -> { cursorDenied.visible = false; @@ -831,13 +825,9 @@ class CharSelectSubState extends MusicBeatSubState } var bopTimer:Float = 0; - var delay = 1 / 24; - var bopFr = 0; - var bopPlay:Bool = false; - var bopRefX:Float = 0; var bopRefY:Float = 0; @@ -957,10 +947,10 @@ class CharSelectSubState extends MusicBeatSubState memb.filters = selectedBizz; memb.scale.set(2.6, 2.6); } - if (controls.ACCEPT && memb.animation.curAnim.name == "confirm") memb.animation.play("confirm"); - if (pressedSelect && controls.BACK) + if (pressedSelect && memb.animation.curAnim.name == "idle") memb.animation.play("confirm"); + if (!pressedSelect && memb.animation.curAnim.name != "idle") { - memb.animation.play("confirm", true, true); + memb.animation.play("confirm", false, true); member.animation.finishCallback = (_) -> { member.animation.play("idle"); member.animation.finishCallback = null; diff --git a/source/funkin/ui/charSelect/IntroSubState.hx b/source/funkin/ui/charSelect/IntroSubState.hx index 04503cbb9..a0c44c225 100644 --- a/source/funkin/ui/charSelect/IntroSubState.hx +++ b/source/funkin/ui/charSelect/IntroSubState.hx @@ -8,22 +8,24 @@ import hxcodec.flixel.FlxVideoSprite; #end import funkin.ui.MusicBeatSubState; import funkin.audio.FunkinSound; +import funkin.save.Save; /** - * After about 2 minutes of inactivity on the title screen, - * the game will enter the Attract state, as a reference to physical arcade machines. - * - * In the current version, this just plays the ~~Kickstarter trailer~~ Erect teaser, but this can be changed to - * gameplay footage, a generic game trailer, or something more elaborate. + * When you first enter the character select state, it will play an introductory video opening up the lights */ class IntroSubState extends MusicBeatSubState { - static final ATTRACT_VIDEO_PATH:String = Paths.stripLibrary(Paths.videos('introSelect')); + static final LIGHTS_VIDEO_PATH:String = Paths.stripLibrary(Paths.videos('introSelect')); var introSound:FunkinSound = null; public override function create():Void { + if (Save.instance.oldChar) + { + onLightsEnd(); + return; + } // Pause existing music. if (FlxG.sound.music != null) { @@ -32,15 +34,20 @@ class IntroSubState extends MusicBeatSubState } #if html5 - trace('Playing web video ${ATTRACT_VIDEO_PATH}'); - playVideoHTML5(ATTRACT_VIDEO_PATH); + trace('Playing web video ${LIGHTS_VIDEO_PATH}'); + playVideoHTML5(LIGHTS_VIDEO_PATH); #end #if hxCodec - trace('Playing native video ${ATTRACT_VIDEO_PATH}'); - playVideoNative(ATTRACT_VIDEO_PATH); + trace('Playing native video ${LIGHTS_VIDEO_PATH}'); + playVideoNative(LIGHTS_VIDEO_PATH); #end + // Im TOO lazy to even care, so uh, yep + FlxG.camera.zoom = 0.66666666666666666666666666666667; + vid.x = -(FlxG.width - (FlxG.width * FlxG.camera.zoom)); + vid.y = -((FlxG.height - (FlxG.height * FlxG.camera.zoom)) * 0.75); + introSound = new FunkinSound(); introSound.loadEmbedded(Paths.sound('CS_Lights')); introSound.pitch = 1; @@ -64,7 +71,7 @@ class IntroSubState extends MusicBeatSubState { vid.zIndex = 0; - vid.finishCallback = onAttractEnd; + vid.finishCallback = onLightsEnd; add(vid); } @@ -88,7 +95,7 @@ class IntroSubState extends MusicBeatSubState if (vid != null) { vid.zIndex = 0; - vid.bitmap.onEndReached.add(onAttractEnd); + vid.bitmap.onEndReached.add(onLightsEnd); add(vid); vid.play(filePath, false); @@ -104,37 +111,33 @@ class IntroSubState extends MusicBeatSubState { super.update(elapsed); - if (controls.ACCEPT) - { - onAttractEnd(); - } + // if (!introSound.paused) + // { + // #if html5 + // @:privateAccess + // vid.netStream.seek(introSound.time); + // #elseif hxCodec + // vid.bitmap.time = Std.int(introSound.time); + // #end + // } } /** - * When the attraction state ends (after the video ends or the user presses any button), - * switch immediately to the title screen. + * When the lights video finishes, it will close the substate */ - function onAttractEnd():Void + function onLightsEnd():Void { - #if html5 - if (vid != null) - { - remove(vid); - } - #end - - #if hxCodec if (vid != null) { + #if hxCodec vid.stop(); + #end remove(vid); + vid.destroy(); + vid = null; } - #end - #if (html5 || hxCodec) - vid.destroy(); - vid = null; - #end + FlxG.camera.zoom = 1; close(); } diff --git a/source/funkin/ui/freeplay/FreeplayDJ.hx b/source/funkin/ui/freeplay/FreeplayDJ.hx index 3d9ffd4d6..13b0d853d 100644 --- a/source/funkin/ui/freeplay/FreeplayDJ.hx +++ b/source/funkin/ui/freeplay/FreeplayDJ.hx @@ -141,6 +141,7 @@ class FreeplayDJ extends FlxAtlasSprite } else if (getCurrentAnimation() == animPrefixB) { + trace("Loss Intro"); var endFrame = playableCharData.getFistPumpIntroBadEndFrame(); if (endFrame > -1 && anim.curFrame >= endFrame) { @@ -166,6 +167,7 @@ class FreeplayDJ extends FlxAtlasSprite } else if (getCurrentAnimation() == animPrefixB) { + trace("Loss GYATT"); var endFrame = playableCharData.getFistPumpLoopBadEndFrame(); if (endFrame > -1 && anim.curFrame >= endFrame) { diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index 79b30ff4d..f5c641d0c 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -273,8 +273,11 @@ class TitleState extends MusicBeatState } #end - if (Save.instance.charactersSeen.contains("pico")) Save.instance.charactersSeen.remove("pico"); - + if (Save.instance.charactersSeen.contains("pico")) + { + Save.instance.charactersSeen.remove("pico"); + Save.instance.oldChar = false; + } Conductor.instance.update(); /* if (FlxG.onMobile) @@ -523,7 +526,8 @@ class TitleState extends MusicBeatState remove(ngSpr); FlxG.camera.flash(FlxColor.WHITE, initialized ? 1 : 4); - remove(credGroup); + + if (credGroup != null) remove(credGroup); skippedIntro = true; } }