diff --git a/buildnumber.txt b/buildnumber.txt index db041382..f9a94625 100644 --- a/buildnumber.txt +++ b/buildnumber.txt @@ -1 +1 @@ -2261 \ No newline at end of file +2265 \ No newline at end of file diff --git a/source/funkin/chart/Chart.hx b/source/funkin/chart/Chart.hx new file mode 100644 index 00000000..c7c28ecc --- /dev/null +++ b/source/funkin/chart/Chart.hx @@ -0,0 +1,172 @@ +package funkin.chart; + +import funkin.system.Song.SwagSong; +import haxe.Json; +import openfl.utils.Assets; + +class Chart { + public static function parse(songName:String, difficulty:String = "normal"):ChartData { + var base:ChartData = { + strumLines: [], + events: [], + meta: { + name: songName, + bpm: 0 + }, + stage: "stage", + codenameChart: true + }; + var chartPath = Paths.chart(songName, difficulty); + if (!Assets.exists(chartPath)) { + Logs.trace('Chart for song ${songName} ($difficulty) at "$chartPath" was not found.', ERROR, RED); + return base; + } + var data:Dynamic = null; + try { + data = Json.parse(Assets.getText(chartPath)); + } catch(e) { + Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED); + } + + if (Reflect.hasField(data, "codenameChart") && Reflect.field(data, "codenameChart") == true) { + return cast data; + } else { + // base fnf chart parsing + var data:SwagSong = data; + if (Reflect.hasField(data, "song")) { + var field:Dynamic = Reflect.field(data, "song"); + if (!(field is String)) + data = field; + } + + base.stage = data.stage; + base.meta.name = data.song; + base.meta.bpm = data.bpm; + + base.strumLines.push({ + characters: [data.player2], + opponent: true, + notes: [] + }); + base.strumLines.push({ + characters: [data.player1], + opponent: false, + notes: [] + }); + + var camFocusedBF:Bool = false; + var beatsPerMesure:Float = data.beatsPerMesure.getDefault(4); + var curBPM:Float = data.bpm; + var curTime:Float = 0; + var curCrochet:Float = ((60 / curBPM) * 1000); + + if (data.notes != null) for(section in data.notes) { + if (section == null) continue; // Yoshi Engine charts crash fix + + if (camFocusedBF != (camFocusedBF = section.mustHitSection)) { + // TODO: auto-add event for cam movement + base.events.push({ + time: curTime, + type: CAM_MOVEMENT, + params: [camFocusedBF ? 1 : 0] + }); + } + + if (section.sectionNotes != null) for(note in section.sectionNotes) { + var daStrumTime:Float = note[0]; + var daNoteData:Int = Std.int(note[1] % 8); + var daNoteType:Int = Std.int(note[1] / 8); + var gottaHitNote:Bool = daNoteData >= 4 ? !section.mustHitSection : section.mustHitSection; + + base.strumLines[gottaHitNote ? 1 : 0].notes.push({ + time: daStrumTime, + id: daNoteData % 4, + type: daNoteType, + sustainLength: note[2] + }); + } + + if (section.changeBPM && section.bpm != curBPM) { + // TODO: BPM CHANGE EVENT + curCrochet = ((60 / section.bpm) * 1000); + } + + curTime += curCrochet * beatsPerMesure; + } + } + return base; + } +} + +typedef ChartData = { + public var strumLines:Array; + public var events:Array; + public var meta:ChartMetaData; + public var codenameChart:Bool; + public var stage:String; +} + +typedef ChartMetaData = { + public var name:String; + public var bpm:Float; + public var ?icon:String; + public var ?color:Dynamic; + public var ?difficulties:Array; + public var ?coopAllowed:Bool; + public var ?opponentModeAllowed:Bool; +} + +typedef ChartStrumLine = { + var characters:Array; + var opponent:Bool; + var notes:Array; + var ?strumLinePos:Float; // 0.25 = default opponent pos, 0.75 = default boyfriend pos +} + +typedef ChartNote = { + var time:Float; // time at which the note will be hit (ms) + var id:Int; // strum id of the note + var type:Int; // type (int) of the note + var sustainLength:Float; // sustain length of the note (ms) +} + +typedef ChartEvent = { + var time:Float; + var type:ChartEventType; + var params:Array; +} + +@:enum +abstract ChartEventType(Int) from Int to Int { + /** + * CUSTOM EVENT + * Params: + * - Function Name (String) + * - Function Parameters... + */ + var CUSTOM = -1; + /** + * NO EVENT, MADE FOR UNKNOWN EVENTS / EVENTS THAT CANNOT BE PARSED + */ + var NONE = 0; + /** + * CAMERA MOVEMENT EVENT + * Params: + * - Target Strumline ID (Int) + */ + var CAM_MOVEMENT = 1; + + /** + * BPM CHANGE EVENT + * Params: + * - Target BPM (Float) + */ + var BPM_CHANGE = 2; + /** + * ALT ANIM TOGGLE + * Params: + * - Strum Line which is going to be toggled (Int) + * - Whenever its going to be toggled or not (Bool) + */ + var ALT_ANIM_TOGGLE = 3; +} \ No newline at end of file diff --git a/source/funkin/chart/chart-model.json b/source/funkin/chart/chart-model.json new file mode 100644 index 00000000..19ba29d6 --- /dev/null +++ b/source/funkin/chart/chart-model.json @@ -0,0 +1,40 @@ +{ + "meta": { + "song": "Test", + "bpm": 120 + }, + "strumLines": [ + { + "characters": ["bf-pixel"], + "opponent": true, + "notes": [ + { + "time": 1500, + "id": 1, + "type": 0, + "sustainLength": 1500 + } + ] + }, + { + "characters": ["bf"], + "opponent": false, + "notes": [ + { + "time": 1500, + "id": 1, + "type": 0, + "sustainLength": 1500 + } + ] + } + ], + "events": [ + { + "time": 1500, + "type": -1, + "params": ["changeShit", true, false] + } + ], + "codenameChart": true +} \ No newline at end of file diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx index b3486849..89b10831 100644 --- a/source/funkin/game/Character.hx +++ b/source/funkin/game/Character.hx @@ -29,9 +29,11 @@ import funkin.scripting.events.PlayAnimEvent.PlayAnimContext; using StringTools; @:allow(funkin.desktop.editors.CharacterEditor) +@:allow(funkin.game.StrumLine) class Character extends FunkinSprite implements IBeatReceiver implements IOffsetCompatible { private var __stunnedTime:Float = 0; + private var __lockAnimThisFrame:Bool = false; public var stunned(default, set):Bool = false; private function set_stunned(b:Bool) { @@ -206,6 +208,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset if (__stunnedTime > 5 / 60) stunned = false; } + __lockAnimThisFrame = false; } private var danced:Bool = false; @@ -256,7 +259,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset public override function beatHit(curBeat:Int) { script.call("beatHit", [curBeat]); - if (danceOnBeat) { + if (danceOnBeat && !__lockAnimThisFrame) { tryDance(); } } diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index d618b50e..45779a8c 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -506,6 +506,8 @@ class PlayState extends MusicBeatState @:dox(hide) override public function create() { + // SCRIPTING & DATA INITIALISATION + #if REGION instance = this; if (FlxG.sound.music != null) FlxG.sound.music.stop(); @@ -538,8 +540,10 @@ class PlayState extends MusicBeatState // String for when the game is paused detailsPausedText = "Paused - " + detailsText; + #end - + // CHARACTER INITIALISATION + #if REGION // Updating Discord Rich Presence. dad = new Character(100, 100, SONG.player2); @@ -563,8 +567,10 @@ class PlayState extends MusicBeatState comboGroup = new FlxSpriteGroup(FlxG.width * 0.55, (FlxG.height * 0.5) - 60); boyfriend = new Character(770, 100, SONG.player1, true); + #end - + // SCRIPTS & STAGE INITIALISATION + #if REGION if (SONG.stage == null || SONG.stage.trim() == "") SONG.stage = "stage"; add(stage = new Stage(SONG.stage)); @@ -587,17 +593,6 @@ class PlayState extends MusicBeatState } } - /** - * PRECACHING - */ - - for(content in Paths.getFolderContent('images/game/score/', true, true)) - FlxG.bitmap.add(content); - - /** - * END OF PRECACHING - */ - scripts.load(); scripts.call("create"); @@ -610,7 +605,16 @@ class PlayState extends MusicBeatState if (dad != null) add(dad); if (boyfriend != null) add(boyfriend); + #end + // PRECACHING + #if REGION + for(content in Paths.getFolderContent('images/game/score/', true, true)) + FlxG.bitmap.add(content); + #end + + // STRUMS & NOTES INITIALISATION + #if REGION strumLine = new FlxObject(0, 50, FlxG.width, 10); strumLine.scrollFactor.set(); @@ -624,7 +628,10 @@ class PlayState extends MusicBeatState add(splashHandler); generateSong(SONG); + #end + // CAMERA & HUD INITIALISATION + #if REGION camFollow = new FlxObject(0, 0, 2, 2); camFollow.setPosition(camPos.x, camPos.y); add(camFollow); @@ -681,6 +688,7 @@ class PlayState extends MusicBeatState for(e in [strumLineNotes, notes, healthBar, healthBarBG, iconP1, iconP2, scoreTxt, missesTxt, accuracyTxt]) e.cameras = [camHUD]; + #end startingSong = true; @@ -1450,7 +1458,7 @@ class PlayState extends MusicBeatState __funcsToExec.push(function(note:Note) { if (__justPressed[note.strumID] && !note.isSustainNote && note.strumLineID == id && !note.wasGoodHit && note.canBeHit) { if (notePerStrum[note.strumID] == null) notePerStrum[note.strumID] = note; - else if (Math.abs(notePerStrum[note.strumID].strumTime - note.strumTime) <= 2) deleteNote(note); + else if (Math.abs(notePerStrum[note.strumID].strumTime - note.strumTime) <= 2) deleteNote(note); else if (note.strumTime < notePerStrum[note.strumID].strumTime) notePerStrum[note.strumID] = note; } }); diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx index 15f05e8a..ebf55606 100644 --- a/source/funkin/game/StrumLine.hx +++ b/source/funkin/game/StrumLine.hx @@ -105,7 +105,6 @@ class StrumLine extends FlxTypedGroup { add(babyArrow); babyArrow.playAnim('static'); - PlayState.instance.strumLineNotes.add(babyArrow); } } diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx index 6701de80..814d4480 100644 --- a/source/funkin/menus/MainMenuState.hx +++ b/source/funkin/menus/MainMenuState.hx @@ -1,5 +1,6 @@ package funkin.menus; +import haxe.Json; import funkin.ui.FunkinText; import funkin.options.Options; import flixel.FlxG; @@ -108,13 +109,9 @@ class MainMenuState extends MusicBeatState if (FlxG.keys.justPressed.SEVEN) FlxG.switchState(new funkin.desktop.DesktopMain()); if (FlxG.keys.justPressed.EIGHT) { - var scr = new funkin.desktop.DesktopScreen(); - var camList = [for(c in FlxG.cameras.list) c]; - for(c in camList) { - FlxG.cameras.remove(c, false); - scr.addCamera(c); - } - cameras = camList; + #if sys + sys.io.File.saveContent("chart.json", Json.stringify(funkin.chart.Chart.parse("dadbattle", "hard"))); + #end } } diff --git a/source/funkin/system/FunkinRatioScaleMode.hx b/source/funkin/system/FunkinRatioScaleMode.hx index 4d49f802..2ab9b43f 100644 --- a/source/funkin/system/FunkinRatioScaleMode.hx +++ b/source/funkin/system/FunkinRatioScaleMode.hx @@ -30,13 +30,16 @@ class FunkinRatioScaleMode extends RatioScaleMode { } @:privateAccess { - FlxG.width = width; - FlxG.height = height; for(c in FlxG.cameras.list) { - c.width = width; - c.height = height; + if (c.width == FlxG.width && c.height == FlxG.height) { + c.width = width; + c.height = height; + } } + + FlxG.width = width; + FlxG.height = height; } }