diff --git a/KadeEngineWithBackground.png b/KadeEngineWithBackground.png index 374a0c1..8629a24 100644 Binary files a/KadeEngineWithBackground.png and b/KadeEngineWithBackground.png differ diff --git a/README.md b/README.md index eaf8060..a1645e9 100644 --- a/README.md +++ b/README.md @@ -24,17 +24,23 @@ If you're looking for documentation, changelogs, or guides, you can find those o # Previews ([skip](#features)) -![Tutorial (Hard) on Downscroll](https://user-images.githubusercontent.com/15311104/113989685-fa5aea80-9850-11eb-9180-f5819a774c79.gif) ![Milf (Hard) on Downscroll](https://user-images.githubusercontent.com/15311104/113990845-2c208100-9852-11eb-8e6d-f1c9e8439871.gif) +![Title Screen](art/readme/KadeEngineTitleScreen.png) -![Roses (Hard) on Upscroll](https://user-images.githubusercontent.com/15311104/113993573-e31dfc00-9854-11eb-82ae-1f29dc8a0b04.png) +![Week Select](art/readme/KadeEngineWeekSelect.png) -![Milf (Hard) on Downscroll](https://user-images.githubusercontent.com/15311104/113991654-f4660900-9852-11eb-8c3d-f3927571f19b.png) +![Freeplay](art/readme/KadeEngineFreeplay.png) -![He malding](https://user-images.githubusercontent.com/15311104/113993693-02b52480-9855-11eb-9975-eb8a7a1be8d1.png) +![Options](art/readme/KadeEngineOptions.png) -![Free Play selection screen](https://i.imgur.com/LR0eWIC.png) +![Senpai Gameplay (Hard, Upscroll)](art/readme/KadeEnginePixelGameplay.png) -![Options Menu](https://i.imgur.com/LBXW9C1.png) +![Roses Dialogue](art/readme/KadeEngineDialogue.png) + +![Pause Screen](art/readme/KadeEnginePauseScreen.png) + +![Results Screen](art/readme/KadeEngineResultsScreen.png) + +![Replay Loader](art/readme/KadeEngineReplayLoader.png) # Features @@ -43,12 +49,15 @@ If you're looking for documentation, changelogs, or guides, you can find those o - **More information during gameplay** - While you're playing, we show you information about how you're doing, such as your accuracy, combo break count, notes per second, and your grade/rating. - **Customizable keybinds** - - Instead of being forced to use WASD and the arrow keys, you can customize the keybinds to any keys you want! + - Instead of being forced to use WASD and the arrow keys, you can set any keybinds you want! - **Replays** (in beta) - Have you ever gotten a crazy score but didn't record? The replay system solves that: it automatically saves a "replay" of your gameplay every time you complete a song, which you can play back inside of the game. - Replays just store information about what you're doing, they don't actually record the screen -- so they take up way less space on your disk than videos. - **Audio offset** - - If your headphones are delayed, you can set an offset in the options menu to line the game up with the delay and play with synced audio like intended. + - If your speakers or headphones are delayed, you can set an offset in the options menu to line the game up with the delay and play with synced audio like intended! + - **And much, much more!** + - There's so much more in store than just what's listed here! If you can imagine a quality of life feature, it's probably + either already included in Kade Engine or is being worked on! # Credits ### Friday Night Funkin' diff --git a/art/readme/KadeEngineDialogue.png b/art/readme/KadeEngineDialogue.png new file mode 100644 index 0000000..36ebeb8 Binary files /dev/null and b/art/readme/KadeEngineDialogue.png differ diff --git a/art/readme/KadeEngineFreeplay.png b/art/readme/KadeEngineFreeplay.png new file mode 100644 index 0000000..a3ed2a9 Binary files /dev/null and b/art/readme/KadeEngineFreeplay.png differ diff --git a/art/readme/KadeEngineOptions.png b/art/readme/KadeEngineOptions.png new file mode 100644 index 0000000..2005272 Binary files /dev/null and b/art/readme/KadeEngineOptions.png differ diff --git a/art/readme/KadeEnginePauseScreen.png b/art/readme/KadeEnginePauseScreen.png new file mode 100644 index 0000000..c31edf7 Binary files /dev/null and b/art/readme/KadeEnginePauseScreen.png differ diff --git a/art/readme/KadeEnginePixelGameplay.png b/art/readme/KadeEnginePixelGameplay.png new file mode 100644 index 0000000..20416ab Binary files /dev/null and b/art/readme/KadeEnginePixelGameplay.png differ diff --git a/art/readme/KadeEngineReplayLoader.png b/art/readme/KadeEngineReplayLoader.png new file mode 100644 index 0000000..4c7fc9c Binary files /dev/null and b/art/readme/KadeEngineReplayLoader.png differ diff --git a/art/readme/KadeEngineResultsScreen.png b/art/readme/KadeEngineResultsScreen.png new file mode 100644 index 0000000..110bade Binary files /dev/null and b/art/readme/KadeEngineResultsScreen.png differ diff --git a/art/readme/KadeEngineTitleScreen.png b/art/readme/KadeEngineTitleScreen.png new file mode 100644 index 0000000..405fe80 Binary files /dev/null and b/art/readme/KadeEngineTitleScreen.png differ diff --git a/art/readme/KadeEngineWeekSelect.png b/art/readme/KadeEngineWeekSelect.png new file mode 100644 index 0000000..d8327c8 Binary files /dev/null and b/art/readme/KadeEngineWeekSelect.png differ diff --git a/source/KadeEngineData.hx b/source/KadeEngineData.hx index 6d0514d..78d86e4 100644 --- a/source/KadeEngineData.hx +++ b/source/KadeEngineData.hx @@ -66,6 +66,9 @@ class KadeEngineData if (FlxG.save.data.distractions == null) FlxG.save.data.distractions = true; + + if (FlxG.save.data.stepMania == null) + FlxG.save.data.stepMania = false; if (FlxG.save.data.flashing == null) FlxG.save.data.flashing = true; diff --git a/source/MenuCharacter.hx b/source/MenuCharacter.hx index 1cf3e5b..9d7a9bb 100644 --- a/source/MenuCharacter.hx +++ b/source/MenuCharacter.hx @@ -1,6 +1,7 @@ package; import flixel.FlxSprite; +import flixel.FlxG; import flixel.graphics.frames.FlxAtlasFrames; class CharacterSetting @@ -33,6 +34,10 @@ class MenuCharacter extends FlxSprite ]; private var flipped:Bool = false; + //questionable variable name lmfao + private var goesLeftNRight:Bool = false; + private var danceLeft:Bool = false; + private var character:String = ''; public function new(x:Int, y:Int, scale:Float, flipped:Bool) { @@ -43,15 +48,17 @@ class MenuCharacter extends FlxSprite frames = Paths.getSparrowAtlas('campaign_menu_UI_characters'); - animation.addByPrefix('bf', "BF idle dance white", 24); + animation.addByPrefix('bf', "BF idle dance white", 24, false); animation.addByPrefix('bfConfirm', 'BF HEY!!', 24, false); - animation.addByPrefix('gf', "GF Dancing Beat WHITE", 24); - animation.addByPrefix('dad', "Dad idle dance BLACK LINE", 24); - animation.addByPrefix('spooky', "spooky dance idle BLACK LINES", 24); - animation.addByPrefix('pico', "Pico Idle Dance", 24); - animation.addByPrefix('mom', "Mom Idle BLACK LINES", 24); - animation.addByPrefix('parents-christmas', "Parent Christmas Idle", 24); - animation.addByPrefix('senpai', "SENPAI idle Black Lines", 24); + animation.addByIndices('gf-left', 'GF Dancing Beat WHITE', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false); + animation.addByIndices('gf-right', 'GF Dancing Beat WHITE', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false); + animation.addByPrefix('dad', "Dad idle dance BLACK LINE", 24, false); + animation.addByIndices('spooky-left', 'spooky dance idle BLACK LINES', [0, 2, 6], "", 12, false); + animation.addByIndices('spooky-right', 'spooky dance idle BLACK LINES', [8, 10, 12, 14], "", 12, false); + animation.addByPrefix('pico', "Pico Idle Dance", 24, false); + animation.addByPrefix('mom', "Mom Idle BLACK LINES", 24, false); + animation.addByPrefix('parents-christmas', "Parent Christmas Idle", 24, false); + animation.addByPrefix('senpai', "SENPAI idle Black Lines", 24, false); setGraphicSize(Std.int(width * scale)); updateHitbox(); @@ -59,6 +66,8 @@ class MenuCharacter extends FlxSprite public function setCharacter(character:String):Void { + var sameCharacter:Bool = character == this.character; + this.character = character; if (character == '') { visible = false; @@ -69,11 +78,33 @@ class MenuCharacter extends FlxSprite visible = true; } - animation.play(character); + if (!sameCharacter) { + bopHead(true); + } var setting:CharacterSetting = settings[character]; offset.set(setting.x, setting.y); setGraphicSize(Std.int(width * setting.scale)); flipX = setting.flipped != flipped; } + + public function bopHead(LastFrame:Bool = false):Void + { + if (character == 'gf' || character == 'spooky') { + danceLeft = !danceLeft; + + if (danceLeft) + animation.play(character + "-left", true); + else + animation.play(character + "-right", true); + } else { + //no spooky nor girlfriend so we do da normal animation + if (animation.name == "bfConfirm") + return; + animation.play(character, true); + } + if (LastFrame) { + animation.finish(); + } + } } diff --git a/source/Note.hx b/source/Note.hx index cefa5ae..1781bd2 100644 --- a/source/Note.hx +++ b/source/Note.hx @@ -17,6 +17,9 @@ class Note extends FlxSprite { public var strumTime:Float = 0; public var baseStrum:Float = 0; + + public var rStrumTime:Float = 0; + public var mustPress:Bool = false; public var noteData:Int = 0; public var rawNoteData:Int = 0; @@ -27,6 +30,8 @@ class Note extends FlxSprite public var modifiedByLua:Bool = false; public var sustainLength:Float = 0; public var isSustainNote:Bool = false; + public var originColor:Int = 0; // The sustain note's original note's color + public var noteSection:Int = 0; public var noteScore:Float = 1; @@ -38,7 +43,12 @@ class Note extends FlxSprite public var rating:String = "shit"; + public var modAngle:Float = 0; // The angle set by modcharts + public var localAngle:Float = 0; // The angle to be edited inside Note.hx + public var dataColor:Array = ['purple', 'blue', 'green', 'red']; + public var quantityColor:Array = [RED_NOTE, 2, BLUE_NOTE, 2, PURP_NOTE, 2, BLUE_NOTE, 2]; + public var arrowAngles:Array = [180, 90, 270, 0]; public var isParent:Bool = false; public var parent:Note = null; @@ -60,10 +70,17 @@ class Note extends FlxSprite x += 50; // MAKE SURE ITS DEFINITELY OFF SCREEN? y -= 2000; + if (inCharter) + { this.strumTime = strumTime; - else + rStrumTime = strumTime; + } + else + { this.strumTime = Math.round(strumTime); + rStrumTime = strumTime - (FlxG.save.data.offset + PlayState.songOffset); + } if (this.strumTime < 0 ) @@ -127,9 +144,27 @@ class Note extends FlxSprite x += swagWidth * noteData; animation.play(dataColor[noteData] + 'Scroll'); + originColor = noteData; // The note's origin color will be checked by its sustain notes - // trace(prevNote); + if (FlxG.save.data.stepMania && !isSustainNote) + { + var strumCheck:Float = rStrumTime; + // I give up on fluctuating bpms. something has to be subtracted from strumCheck to make them look right but idk what. + // I'd use the note's section's start time but neither the note's section nor its start time are accessible by themselves + //strumCheck -= ??? + + var ind:Int = Std.int(Math.round(strumCheck / (Conductor.stepCrochet / 2))); + + var col:Int = 0; + col = quantityColor[ind % 8]; // Set the color depending on the beats + + animation.play(dataColor[col] + 'Scroll'); + localAngle -= arrowAngles[col]; + localAngle += arrowAngles[noteData]; + originColor = col; + } + // we make sure its downscroll and its a SUSTAIN NOTE (aka a trail, not a note) // and flip it so it doesn't look weird. // THIS DOESN'T FUCKING FLIP THE NOTE, CONTRIBUTERS DON'T JUST COMMENT THIS OUT JESUS @@ -144,8 +179,9 @@ class Note extends FlxSprite x += width / 2; - animation.play(dataColor[noteData] + 'holdend'); + originColor = prevNote.originColor; + animation.play(dataColor[originColor] + 'holdend'); // This works both for normal colors and quantization colors updateHitbox(); x -= width / 2; @@ -158,7 +194,7 @@ class Note extends FlxSprite if (prevNote.isSustainNote) { - prevNote.animation.play(dataColor[prevNote.noteData] + 'hold'); + prevNote.animation.play(dataColor[prevNote.originColor] + 'hold'); if(FlxG.save.data.scrollSpeed != 1) prevNote.scale.y *= Conductor.stepCrochet / 100 * 1.5 * FlxG.save.data.scrollSpeed; @@ -173,6 +209,7 @@ class Note extends FlxSprite override function update(elapsed:Float) { super.update(elapsed); + angle = modAngle + localAngle; if (!modifiedByLua) if (!sustainActive) diff --git a/source/Options.hx b/source/Options.hx index 574092f..10eb0b0 100644 --- a/source/Options.hx +++ b/source/Options.hx @@ -244,6 +244,26 @@ class DistractionsAndEffectsOption extends Option } } +class StepManiaOption extends Option +{ + public function new(desc:String) + { + super(); + description = desc; + } + public override function press():Bool + { + FlxG.save.data.stepMania = !FlxG.save.data.stepMania; + display = updateDisplay(); + return true; + } + + private override function updateDisplay():String + { + return "Colors by quantization " + (!FlxG.save.data.stepMania ? "off" : "on"); + } +} + class ResetButtonOption extends Option { public function new(desc:String) @@ -833,6 +853,7 @@ class ResetSettings extends Option FlxG.save.data.strumline = null; FlxG.save.data.customStrumLine = null; FlxG.save.data.camzoom = null; + FlxG.save.data.stepMania = null; KadeEngineData.initSave(); confirm = false; trace('All settings have been reset'); diff --git a/source/OptionsMenu.hx b/source/OptionsMenu.hx index 62d3091..f953f01 100644 --- a/source/OptionsMenu.hx +++ b/source/OptionsMenu.hx @@ -42,10 +42,11 @@ class OptionsMenu extends MusicBeatState new OptionCategory("Appearance", [ new DistractionsAndEffectsOption("Toggle stage distractions that can hinder your gameplay."), new CamZoomOption("Toggle the camera zoom in-game."), - new RainbowFPSOption("Make the FPS Counter Rainbow"), + new StepManiaOption("Sets the colors of the arrows depending on quantization instead of direction."), new AccuracyOption("Display accuracy information."), - new NPSDisplayOption("Shows your current Notes Per Second."), new SongPositionOption("Show the songs current position (as a bar)"), + new NPSDisplayOption("Shows your current Notes Per Second."), + new RainbowFPSOption("Make the FPS Counter Rainbow"), new CpuStrums("CPU's strumline lights up when a note hits it."), ]), diff --git a/source/PlayState.hx b/source/PlayState.hx index 626d4d0..e604ec5 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -241,6 +241,7 @@ class PlayState extends MusicBeatState // Animation common suffixes private var dataSuffix:Array = ['LEFT', 'DOWN', 'UP', 'RIGHT']; + private var dataColor:Array = ['purple', 'blue', 'green', 'red']; // API stuff @@ -1878,73 +1879,23 @@ class PlayState extends MusicBeatState babyArrow.animation.add('confirm', [12, 16], 24, false); } - case 'normal': - babyArrow.frames = Paths.getSparrowAtlas('NOTE_assets'); - babyArrow.animation.addByPrefix('green', 'arrowUP'); - babyArrow.animation.addByPrefix('blue', 'arrowDOWN'); - babyArrow.animation.addByPrefix('purple', 'arrowLEFT'); - babyArrow.animation.addByPrefix('red', 'arrowRIGHT'); - - babyArrow.antialiasing = true; - babyArrow.setGraphicSize(Std.int(babyArrow.width * 0.7)); - - switch (Math.abs(i)) - { - case 2: - babyArrow.x += Note.swagWidth * 2; - babyArrow.animation.addByPrefix('static', 'arrowUP'); - babyArrow.animation.addByPrefix('pressed', 'up press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'up confirm', 24, false); - case 3: - babyArrow.x += Note.swagWidth * 3; - babyArrow.animation.addByPrefix('static', 'arrowRIGHT'); - babyArrow.animation.addByPrefix('pressed', 'right press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'right confirm', 24, false); - case 1: - babyArrow.x += Note.swagWidth * 1; - babyArrow.animation.addByPrefix('static', 'arrowDOWN'); - babyArrow.animation.addByPrefix('pressed', 'down press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'down confirm', 24, false); - case 0: - babyArrow.x += Note.swagWidth * 0; - babyArrow.animation.addByPrefix('static', 'arrowLEFT'); - babyArrow.animation.addByPrefix('pressed', 'left press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'left confirm', 24, false); - } - default: babyArrow.frames = Paths.getSparrowAtlas('NOTE_assets'); - babyArrow.animation.addByPrefix('green', 'arrowUP'); - babyArrow.animation.addByPrefix('blue', 'arrowDOWN'); - babyArrow.animation.addByPrefix('purple', 'arrowLEFT'); - babyArrow.animation.addByPrefix('red', 'arrowRIGHT'); + for (j in 0...4) + { + babyArrow.animation.addByPrefix(dataColor[j], 'arrow' + dataSuffix[j]); + } + + var lowerDir:String = dataSuffix[i].toLowerCase(); + + babyArrow.animation.addByPrefix('static', 'arrow' + dataSuffix[i]); + babyArrow.animation.addByPrefix('pressed', lowerDir + ' press', 24, false); + babyArrow.animation.addByPrefix('confirm', lowerDir + ' confirm', 24, false); + + babyArrow.x += Note.swagWidth * i; babyArrow.antialiasing = true; babyArrow.setGraphicSize(Std.int(babyArrow.width * 0.7)); - - switch (Math.abs(i)) - { - case 2: - babyArrow.x += Note.swagWidth * 2; - babyArrow.animation.addByPrefix('static', 'arrowUP'); - babyArrow.animation.addByPrefix('pressed', 'up press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'up confirm', 24, false); - case 3: - babyArrow.x += Note.swagWidth * 3; - babyArrow.animation.addByPrefix('static', 'arrowRIGHT'); - babyArrow.animation.addByPrefix('pressed', 'right press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'right confirm', 24, false); - case 1: - babyArrow.x += Note.swagWidth * 1; - babyArrow.animation.addByPrefix('static', 'arrowDOWN'); - babyArrow.animation.addByPrefix('pressed', 'down press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'down confirm', 24, false); - case 0: - babyArrow.x += Note.swagWidth * 0; - babyArrow.animation.addByPrefix('static', 'arrowLEFT'); - babyArrow.animation.addByPrefix('pressed', 'left press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'left confirm', 24, false); - } } babyArrow.updateHitbox(); @@ -2790,18 +2741,6 @@ class PlayState extends MusicBeatState // Accessing the animation name directly to play it var singData:Int = Std.int(Math.abs(daNote.noteData)); dad.playAnim('sing' + dataSuffix[singData] + altAnim, true); - - switch (Math.abs(daNote.noteData)) - { - case 2: - dad.playAnim('singUP' + altAnim, true); - case 3: - dad.playAnim('singRIGHT' + altAnim, true); - case 1: - dad.playAnim('singDOWN' + altAnim, true); - case 0: - dad.playAnim('singLEFT' + altAnim, true); - } if (FlxG.save.data.cpuStrums) { @@ -2847,6 +2786,8 @@ class PlayState extends MusicBeatState daNote.angle = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].angle; if (daNote.sustainActive) daNote.alpha = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].alpha; + daNote.modAngle = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].angle; + daNote.alpha = playerStrums.members[Math.floor(Math.abs(daNote.noteData))].alpha; } else if (!daNote.wasGoodHit && !daNote.modifiedByLua) { @@ -2856,6 +2797,8 @@ class PlayState extends MusicBeatState daNote.angle = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].angle; if (daNote.sustainActive) daNote.alpha = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].alpha; + daNote.modAngle = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].angle; + daNote.alpha = strumLineNotes.members[Math.floor(Math.abs(daNote.noteData))].alpha; } if (daNote.isSustainNote) diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx index d2362ee..8f87cef 100644 --- a/source/StoryMenuState.hx +++ b/source/StoryMenuState.hx @@ -323,6 +323,9 @@ class StoryMenuState extends MusicBeatState FlxG.switchState(new MainMenuState()); } + if (FlxG.sound.music != null) + Conductor.songPosition = FlxG.sound.music.time; + super.update(elapsed); } @@ -474,4 +477,13 @@ class StoryMenuState extends MusicBeatState FlxG.save.data.weekUnlocked = weekUnlocked.length - 1; FlxG.save.flush(); } + + override function beatHit() + { + super.beatHit(); + + grpWeekCharacters.members[0].bopHead(); + grpWeekCharacters.members[1].bopHead(); + grpWeekCharacters.members[2].bopHead(); + } }