From 04d81514d1b47f020696f1aca9c1dd63c9534057 Mon Sep 17 00:00:00 2001
From: TheRealJake_12 <84357907+TheRealJake12@users.noreply.github.com>
Date: Sun, 15 Dec 2024 15:10:10 -0600
Subject: [PATCH] major fixes
switch to moonchart chart converter
can convert the following with little issue
- Legacy
- Psych
- Kade
- VSlice (only 1 diff at a time)
fixed middle scroll
temporarily removed opponent mode because it's messy and I'm going to redo it
fixed sustains not going transparent when missed
---
.hxpkg | 69 +--
Project.xml | 1 +
assets/shared/data/editors/charter.xml | 53 +-
source/Init.hx | 1 +
.../flixel/graphics/tile/FlxDrawQuadsItem.hx | 151 -----
source/import.hx | 10 +-
source/kec/backend/PlayStateChangeables.hx | 4 +-
source/kec/backend/Ratings.hx | 34 +-
source/kec/backend/chart/ChartConverter.hx | 534 +++++-------------
.../chart/{format/Modern.hx => ChartData.hx} | 4 +-
.../kec/backend/chart/{format => }/Section.hx | 2 +-
source/kec/backend/chart/Song.hx | 75 +--
source/kec/backend/chart/TimingStruct.hx | 4 +-
source/kec/backend/chart/format/Legacy.hx | 24 -
.../kec/backend/chart/format/LegacySection.hx | 12 -
.../kec/backend/chart/format/PsychFormat.hx | 29 -
source/kec/backend/lua/ModchartState.hx | 9 -
source/kec/backend/tools/ArraySortTools.hx | 164 ++++++
source/kec/backend/tools/ArrayTools.hx | 106 ++++
source/kec/backend/tools/FloatTools.hx | 24 +
source/kec/backend/tools/ICloneable.hx | 10 +
source/kec/backend/tools/Int64Tools.hx | 43 ++
source/kec/backend/tools/IntTools.hx | 16 +
source/kec/backend/tools/IteratorTools.hx | 35 ++
source/kec/backend/tools/MapTools.hx | 89 +++
.../StringTool.hx => tools/StringTools.hx} | 4 +-
source/kec/backend/util/DiffCalc.hx | 4 +-
source/kec/backend/util/FileDialogHandler.hx | 249 ++++++++
source/kec/backend/util/Paths.hx | 8 +
source/kec/backend/util/smTools/SMFile.hx | 288 ----------
source/kec/backend/util/smTools/SMHeader.hx | 120 ----
source/kec/backend/util/smTools/SMMeasure.hx | 29 -
source/kec/backend/util/smTools/SMNote.hx | 15 -
source/kec/objects/Character.hx | 2 +-
source/kec/objects/editor/EditorGrid.hx | 2 +-
source/kec/objects/note/Note.hx | 76 +--
source/kec/objects/note/NoteSplash.hx | 2 +-
source/kec/objects/note/StaticArrow.hx | 15 +-
source/kec/objects/ui/HealthIcon.hx | 14 +-
source/kec/states/FreeplayState.hx | 121 +---
source/kec/states/GameplayCustomizeState.hx | 87 +--
source/kec/states/MainMenuState.hx | 1 -
source/kec/states/MusicBeatState.hx | 6 +-
source/kec/states/PlayState.hx | 270 +++------
source/kec/states/SelectEditorsState.hx | 1 -
source/kec/states/StoryMenuState.hx | 12 -
.../states/editors/CharacterEditorState.hx | 1 +
source/kec/states/editors/ChartingState.hx | 276 +++++----
source/kec/states/editors/StageDebugState.hx | 1 -
source/kec/substates/GameOverSubstate.hx | 5 +-
source/kec/substates/ResultsScreen.hx | 2 +-
51 files changed, 1343 insertions(+), 1771 deletions(-)
delete mode 100644 source/flixel/graphics/tile/FlxDrawQuadsItem.hx
rename source/kec/backend/chart/{format/Modern.hx => ChartData.hx} (88%)
rename source/kec/backend/chart/{format => }/Section.hx (87%)
delete mode 100644 source/kec/backend/chart/format/Legacy.hx
delete mode 100644 source/kec/backend/chart/format/LegacySection.hx
delete mode 100644 source/kec/backend/chart/format/PsychFormat.hx
create mode 100644 source/kec/backend/tools/ArraySortTools.hx
create mode 100644 source/kec/backend/tools/ArrayTools.hx
create mode 100644 source/kec/backend/tools/FloatTools.hx
create mode 100644 source/kec/backend/tools/ICloneable.hx
create mode 100644 source/kec/backend/tools/Int64Tools.hx
create mode 100644 source/kec/backend/tools/IntTools.hx
create mode 100644 source/kec/backend/tools/IteratorTools.hx
create mode 100644 source/kec/backend/tools/MapTools.hx
rename source/kec/backend/{util/StringTool.hx => tools/StringTools.hx} (98%)
create mode 100644 source/kec/backend/util/FileDialogHandler.hx
delete mode 100644 source/kec/backend/util/smTools/SMFile.hx
delete mode 100644 source/kec/backend/util/smTools/SMHeader.hx
delete mode 100644 source/kec/backend/util/smTools/SMMeasure.hx
delete mode 100644 source/kec/backend/util/smTools/SMNote.hx
diff --git a/.hxpkg b/.hxpkg
index 2a30b5a2..df26cbb7 100644
--- a/.hxpkg
+++ b/.hxpkg
@@ -1,68 +1 @@
-[
- {
- "profile": "default",
- "pkgs": [
- {
- "name": "flixel"
- },
- {
- "name": "openfl"
- },
- {
- "name": "lime"
- },
- {
- "name": "flixel-tools"
- },
- {
- "name": "flixel-addons"
- },
- {
- "name": "flixel-text-input"
- },
- {
- "name": "hxcpp-debug-server"
- },
- {
- "name": "polymod",
- "link": "https://github.com/swordcube/scriptless-polymod.git"
- },
- {
- "name": "hxvlc"
- },
- {
- "name": "hscript"
- },
- {
- "name": "hxdiscord_rpc",
- "link": "https://github.com/MAJigsaw77/hxdiscord_rpc.git"
- },
- {
- "name": "haxeui-core",
- "link": "https://github.com/haxeui/haxeui-core.git"
- },
- {
- "name": "haxeui-flixel",
- "link": "https://github.com/haxeui/haxeui-flixel.git"
- },
- {
- "name": "hxcpp"
- },
- {
- "name": "thx.semver"
- },
- {
- "name": "thx.core",
- "link": "https://github.com/fponticelli/thx.core.git"
- },
- {
- "name": "linc_luajit",
- "link": "https://github.com/superpowers04/linc_luajit"
- },
- {
- "name": "hscript-improved",
- "link": "https://github.com/FNF-CNE-Devs/hscript-improved.git"
- }
- ]
- }
-]
\ No newline at end of file
+[{"profile":"default","pkgs":[{"name":"flixel"},{"name":"openfl"},{"name":"lime"},{"name":"flixel-tools"},{"name":"flixel-addons"},{"name":"flixel-text-input"},{"name":"hxcpp-debug-server"},{"name":"polymod","link":"https://github.com/swordcube/scriptless-polymod.git"},{"name":"hxvlc"},{"name":"hscript"},{"name":"hxdiscord_rpc","link":"https://github.com/MAJigsaw77/hxdiscord_rpc.git"},{"name":"haxeui-core","link":"https://github.com/haxeui/haxeui-core.git"},{"name":"haxeui-flixel","link":"https://github.com/haxeui/haxeui-flixel.git"},{"name":"hxcpp"},{"name":"thx.semver"},{"name":"thx.core","link":"https://github.com/fponticelli/thx.core.git"},{"name":"linc_luajit","link":"https://github.com/superpowers04/linc_luajit"},{"name":"hscript-improved","link":"https://github.com/FNF-CNE-Devs/hscript-improved.git"},{"name":"moonchart","link":"https://github.com/MaybeMaru/moonchart.git"}]}]
\ No newline at end of file
diff --git a/Project.xml b/Project.xml
index a35cc6fd..7341ac9e 100644
--- a/Project.xml
+++ b/Project.xml
@@ -86,6 +86,7 @@
+
diff --git a/assets/shared/data/editors/charter.xml b/assets/shared/data/editors/charter.xml
index 18464c6d..4261af0e 100644
--- a/assets/shared/data/editors/charter.xml
+++ b/assets/shared/data/editors/charter.xml
@@ -47,19 +47,19 @@
-
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
@@ -67,7 +67,7 @@
-
+
@@ -84,8 +84,37 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/Init.hx b/source/Init.hx
index cb23bbf0..06e80ab5 100644
--- a/source/Init.hx
+++ b/source/Init.hx
@@ -27,6 +27,7 @@ class Init extends MusicBeatState
kec.backend.KeyBinds.keyCheck();
FilterUtils.initializeFilters();
+ kec.backend.Discord.load();
FilterUtils.setColorBlindess(FlxG.save.data.colorblind);
diff --git a/source/flixel/graphics/tile/FlxDrawQuadsItem.hx b/source/flixel/graphics/tile/FlxDrawQuadsItem.hx
deleted file mode 100644
index 14a4429f..00000000
--- a/source/flixel/graphics/tile/FlxDrawQuadsItem.hx
+++ /dev/null
@@ -1,151 +0,0 @@
-package flixel.graphics.tile;
-
-#if FLX_DRAW_QUADS
-import flixel.FlxCamera;
-import flixel.graphics.frames.FlxFrame;
-import flixel.graphics.tile.FlxDrawBaseItem.FlxDrawItemType;
-import flixel.math.FlxMatrix;
-import flixel.system.FlxAssets.FlxShader;
-import openfl.Vector;
-import openfl.display.ShaderParameter;
-import openfl.geom.ColorTransform;
-
-class FlxDrawQuadsItem extends FlxDrawBaseItem
-{
- static inline var VERTICES_PER_QUAD = #if (openfl >= "8.5.0") 4 #else 6 #end;
-
- public var shader:FlxShader;
-
- var rects:Vector;
- var transforms:Vector;
- var alphas:Array;
- var colorMultipliers:Array;
- var colorOffsets:Array;
-
- public function new()
- {
- super();
- type = FlxDrawItemType.TILES;
- rects = new Vector();
- transforms = new Vector();
- alphas = [];
- }
-
- override public function reset():Void
- {
- super.reset();
- rects.length = 0;
- transforms.length = 0;
- alphas.splice(0, alphas.length);
- if (colorMultipliers != null)
- colorMultipliers.splice(0, colorMultipliers.length);
- if (colorOffsets != null)
- colorOffsets.splice(0, colorOffsets.length);
- }
-
- override public function dispose():Void
- {
- super.dispose();
- rects = null;
- transforms = null;
- alphas = null;
- colorMultipliers = null;
- colorOffsets = null;
- }
-
- override public function addQuad(frame:FlxFrame, matrix:FlxMatrix, ?transform:ColorTransform):Void
- {
- var rect = frame.frame;
- rects.push(rect.x);
- rects.push(rect.y);
- rects.push(rect.width);
- rects.push(rect.height);
-
- transforms.push(matrix.a);
- transforms.push(matrix.b);
- transforms.push(matrix.c);
- transforms.push(matrix.d);
- transforms.push(matrix.tx);
- transforms.push(matrix.ty);
-
- for (i in 0...VERTICES_PER_QUAD)
- alphas.push(transform != null ? transform.alphaMultiplier : 1.0);
-
- if (colored || hasColorOffsets)
- {
- if (colorMultipliers == null)
- colorMultipliers = [];
-
- if (colorOffsets == null)
- colorOffsets = [];
-
- for (i in 0...VERTICES_PER_QUAD)
- {
- if (transform != null)
- {
- colorMultipliers.push(transform.redMultiplier);
- colorMultipliers.push(transform.greenMultiplier);
- colorMultipliers.push(transform.blueMultiplier);
-
- colorOffsets.push(transform.redOffset);
- colorOffsets.push(transform.greenOffset);
- colorOffsets.push(transform.blueOffset);
- colorOffsets.push(transform.alphaOffset);
- }
- else
- {
- colorMultipliers.push(1);
- colorMultipliers.push(1);
- colorMultipliers.push(1);
-
- colorOffsets.push(0);
- colorOffsets.push(0);
- colorOffsets.push(0);
- colorOffsets.push(0);
- }
-
- colorMultipliers.push(1);
- }
- }
- }
-
- #if !flash
- override public function render(camera:FlxCamera):Void
- {
- if (rects.length == 0)
- return;
-
- var shader = shader != null ? shader : graphics.shader;
- if (shader == null)
- return;
- var bitmap = graphics.bitmap;
- shader.bitmap.input = bitmap;
- shader.bitmap.filter = (camera.antialiasing || antialiasing) ? LINEAR : NEAREST;
- shader.alpha.value = alphas;
-
- if (colored || hasColorOffsets)
- {
- shader.colorMultiplier.value = colorMultipliers;
- shader.colorOffset.value = colorOffsets;
- }
-
- setParameterValue(shader.hasTransform, true);
- setParameterValue(shader.hasColorTransform, colored || hasColorOffsets);
-
- #if (openfl > "8.7.0")
- camera.canvas.graphics.overrideBlendMode(blend);
- #end
- camera.canvas.graphics.beginShaderFill(shader);
- camera.canvas.graphics.drawQuads(rects, null, transforms);
- super.render(camera);
- }
-
- inline function setParameterValue(parameter:ShaderParameter, value:Bool):Void
- {
- if (parameter.value == null)
- parameter.value = [];
- parameter.value[0] = value;
- }
- #end
-}
-#end
diff --git a/source/import.hx b/source/import.hx
index 9927dd72..f167eac7 100644
--- a/source/import.hx
+++ b/source/import.hx
@@ -31,5 +31,13 @@ import kec.backend.Constants;
import kec.backend.util.Sort;
#end
+using Lambda;
using StringTools;
-using kec.backend.util.StringTool;
+using kec.backend.tools.ArraySortTools;
+using kec.backend.tools.ArrayTools;
+using kec.backend.tools.FloatTools;
+using kec.backend.tools.Int64Tools;
+using kec.backend.tools.IntTools;
+using kec.backend.tools.IteratorTools;
+using kec.backend.tools.MapTools;
+using kec.backend.tools.StringTools;
diff --git a/source/kec/backend/PlayStateChangeables.hx b/source/kec/backend/PlayStateChangeables.hx
index 15b1e558..fbd18342 100644
--- a/source/kec/backend/PlayStateChangeables.hx
+++ b/source/kec/backend/PlayStateChangeables.hx
@@ -5,7 +5,7 @@ class PlayStateChangeables
public static var modchart:Bool;
public static var mirrorMode:Bool;
public static var healthDrain:Bool;
- public static var opponentMode:Bool;
+ // public static var opponentMode:Bool;
public static var skillIssue:Bool;
public static var practiceMode:Bool;
public static var holds:Bool;
@@ -13,9 +13,7 @@ class PlayStateChangeables
public static var healthLoss:Float;
public static var useDownscroll:Bool;
public static var middleScroll:Bool;
- public static var safeFrames:Int;
public static var botPlay:Bool;
public static var zoom:Float;
- public static var scrollSpeed:Float = 1.0;
public static var noteCamera:Bool;
}
diff --git a/source/kec/backend/Ratings.hx b/source/kec/backend/Ratings.hx
index aad18f17..b5447cf8 100644
--- a/source/kec/backend/Ratings.hx
+++ b/source/kec/backend/Ratings.hx
@@ -33,7 +33,7 @@ class Ratings
public static function GenerateLetterRank(accuracy:Float)
{
var letterRanking:String = "";
- var wifeConditions:Array = [
+ final wifeConditions:Array = [
accuracy >= 99.9935, // AAAAA
accuracy >= 99.980, // AAAA:
accuracy >= 99.970, // AAAA.
@@ -54,7 +54,7 @@ class Ratings
for (i in 0...wifeConditions.length)
{
- var b = wifeConditions[i];
+ final b = wifeConditions[i];
if (b)
{
@@ -127,27 +127,15 @@ class Ratings
public static function CalculateRanking(score:Int, nps:Int, maxNPS:Int, accuracy:Float):String
{
- return (FlxG.save.data.npsDisplay ? // NPS Toggle
- "NPS: "
- + nps
- + " (Max "
- + maxNPS
- + ")"
- + (!PlayStateChangeables.botPlay ? " | " : "") : "") + // NPS
- (!PlayStateChangeables.botPlay ? "Score:" + score + // Score
- (FlxG.save.data.accuracyDisplay ? // Accuracy Toggle
- " | Combo Breaks:"
- + Stats.misses // Misses/Combo Breaks
- + (!FlxG.save.data.healthBar ? " | Health:"
- + (!PlayStateChangeables.opponentMode ? Math.round(PlayState.instance.health * 50) : Math.round(100 - (PlayState.instance.health * 50)))
- + "%" : "")
- + " | Accuracy:"
- + (PlayStateChangeables.botPlay ? "N/A" : HelperFunctions.truncateFloat(accuracy, 2) + " %")
- + // Accuracy
- " | "
- + GenerateComboRank(accuracy)
- + " "
- + (!PlayStateChangeables.practiceMode ? GenerateLetterRank(accuracy) : 'PRACTICE') : "") : ""); // Letter Rank
+ final npsString:String = FlxG.save.data.npsDisplay ? 'NPS: $nps (Max $maxNPS) | ' : '';
+ final scoreString:String = 'Score: $score | ';
+ final breakString:String = FlxG.save.data.accuracyDisplay ? 'Combo Breaks: ${Stats.misses} | ' : '';
+ final health:String = FlxG.save.data.healthBar ? '' : 'Health: ${Math.round(PlayState.instance.health * 50)}% | ';
+ final accuracyString:String = 'Accuracy: ${HelperFunctions.truncateFloat(accuracy, 2)}% ';
+ final comboRank:String = GenerateComboRank(accuracy);
+ final letterRank:String = !PlayStateChangeables.practiceMode ? GenerateLetterRank(accuracy) : 'PRACTICE';
+
+ return '$npsString$scoreString$breakString$health$accuracyString$comboRank $letterRank';
}
}
diff --git a/source/kec/backend/chart/ChartConverter.hx b/source/kec/backend/chart/ChartConverter.hx
index adc7d4cd..55262389 100644
--- a/source/kec/backend/chart/ChartConverter.hx
+++ b/source/kec/backend/chart/ChartConverter.hx
@@ -1,6 +1,11 @@
package kec.backend.chart;
-import kec.backend.chart.format.*;
+import moonchart.formats.fnf.FNFKade.FNFKadeFormat;
+import openfl.utils.Assets as OpenFlAssets;
+import moonchart.formats.fnf.*;
+import moonchart.formats.fnf.legacy.*;
+
+using kec.backend.tools.StringTools;
/**
* ### Tool To Convert Chart Formats.
@@ -8,214 +13,123 @@ import kec.backend.chart.format.*;
*/
class ChartConverter
{
- public static function convertEtc(song:Dynamic):Modern
+ public static function convert(data:Dynamic, name:String, diff:String):ChartData
{
- final data:Legacy = cast song.song;
- data.eventObjects = checkEvents(data);
- if (data.audioFile == null)
- data.audioFile = StringTools.replace(data.song, "-", " ").toLowerCase();
- if (data.songId == null)
- data.songId = StringTools.replace(data.song, "-", " ").toLowerCase();
- if (data.songName == null)
- data.songName = data.song;
-
- var currentIndex = 0;
- var index = 0;
- var ba = song.bpm;
-
- data.style = "Default";
-
- if (data.gfVersion == null)
- data.gfVersion = "gf";
-
- if (data.stage == null)
- data.stage = "stage";
-
- if (data.splitVoiceTracks == null)
- data.splitVoiceTracks = false;
+ final formattedName:String = Paths.formatToSongPath(name);
+ final diffi:String = StringTools.replace(diff, '-', '');
+ final chart:Dynamic = (data.song == null) ? data : ((data.song is String) ? data : data.song);
- // If the song has null sections.
- if (data.notes == null)
+ if (chart == null)
{
- data.notes = [];
- data.notes.push(Song.oldSection(data));
+ Debug.logWarn('$formattedName was null');
+ return null;
}
- // If the section array exists but there's nothing we push at least 1 section to play.
- if (data.notes.length == 0)
- data.notes.push(Song.oldSection(song));
+ // if else if else if else simulator
+ final toFind:String = 'data/songs/$formattedName/$formattedName$diff';
- var newNotes:Array = [];
- TimingStruct.clearTimings();
-
- for (i in data.eventObjects)
+ if (chart?.chartVersion == 'KEC1')
{
- if (i.type == "BPM Change")
- {
- var beat:Float = i.beat * Conductor.rate;
-
- var endBeat:Float = Math.POSITIVE_INFINITY;
-
- TimingStruct.addTiming(beat, i.args[0] * Conductor.rate, endBeat, 0); // offset in this case = start time since we don't have a offset
-
- if (currentIndex != 0)
- {
- var data = TimingStruct.AllTimings[currentIndex - 1];
- data.endBeat = beat;
- data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
- var step = ((60 / data.bpm) * 1000) / 4;
- TimingStruct.AllTimings[currentIndex].startStep = Math.floor(((data.endBeat / (data.bpm / 60)) * 1000) / step);
- TimingStruct.AllTimings[currentIndex].startTime = data.startTime + data.length;
- }
-
- currentIndex++;
- }
+ return convertKEC1(data);
}
- for (i => section in data.notes)
- {
- section.index = i;
- final currentBeat = 4 * index;
- final currentSeg = TimingStruct.getTimingAtBeat(currentBeat);
- newNotes.push({
- index: i,
- sectionNotes: [],
- bpm: currentSeg.bpm,
- mustHitSection: section.mustHitSection,
- lengthInSteps: 16,
- startTime: currentSeg.startTime,
- }); // create a blank for now
- if (section.lengthInSteps == null)
- section.lengthInSteps = 16;
+ // Debug.logTrace((data.song is String) ? "Unwrapped" : "Wrapped");
+ // Debug.logTrace((data.song == null) ? "Was Null" : "Wasn't Null");
+ final chartPath:String = OpenFlAssets.getPath(Paths.json(toFind));
- if (currentSeg == null)
- continue;
-
- final beat:Float = currentSeg.startBeat + (currentBeat - currentSeg.startBeat);
+ if (Reflect.hasField(chart.notes[0], "sectionBeats"))
+ {
+ final psych = new FNFPsych().fromFile(chartPath, null, diffi);
+ final kade = new FNFKade().fromFormat(psych, diffi);
+ Debug.logTrace('Psych To Kade For $name with diff $diff');
+ return compat(kade.data.song);
+ }
- if (section.changeBPM && section.bpm != ba)
- {
- ba = section.bpm;
- data.eventObjects.push({
- name: "FNF BPM Change " + section.index,
- beat: beat,
- args: [section.bpm],
- type: "BPM Change"
- });
- }
- var fard:Int = 0;
+ if (Reflect.hasField(chart, "generatedBy"))
+ {
+ final metaPath:String = OpenFlAssets.getPath(Paths.json('data/songs/$formattedName/metadata'));
+ final vslice = new FNFVSlice().fromFile(chartPath, metaPath, diffi);
+ final kade = new FNFKade().fromFormat(vslice, diffi);
+ Debug.logTrace('VSlice To Kade For $name with diff $diff');
+ // Debug.logTrace('${vslice.meta.songName} ${kade.data.song.songId}');
+ return compat(kade.data.song, vslice.meta.songName);
+ }
- for (ii in section.sectionNotes)
- {
- // try not to brick the game challenge (impossible (thanks bolo))
- if (section.mustHitSection)
- {
- var bool = false;
- if (ii[1] <= 3)
- {
- ii[1] += 4;
- bool = true;
- }
- if (ii[1] > 3)
- if (!bool)
- ii[1] -= 4;
- }
+ if (Reflect.hasField(chart.notes[0], "altAnim") || Reflect.hasField(chart.notes[0], "typeOfSection"))
+ {
+ final legacy = new FNFLegacy().fromFile(chartPath, null, diffi);
+ final kade = new FNFKade().fromFormat(legacy, diffi);
+ Debug.logTrace('Legacy To Kade For $name with diff $diff');
+ return compat(kade.data.song);
+ }
- if (ii[3] == null)
- ii[3] = "Normal";
+ if (Reflect.hasField(chart, "chartVersion") || Reflect.hasField(chart, "eventObjects"))
+ {
+ final kadeOne = new FNFKade().fromFile(chartPath, null, diffi);
+ Debug.logTrace('Kade For $name with diff $diff');
+ return compat(kadeOne.data.song);
+ }
- final strumTime = ii[0];
- final noteData = ii[1];
- final holdLength = ii[2];
- final nType = ii[3];
+ // because conversion isn't perfect
+ Debug.logTrace("No Format Could Be Found. Force Convert From Legacy Anyway.");
+ final legacy = new FNFLegacy().fromFile(chartPath, null, diffi);
+ final kade = new FNFKade().fromFormat(legacy, diffi);
+ Debug.logTrace('Legacy To Kade For $name with diff $diff');
+ return compat(kade.data.song);
+ }
- ii.resize(0);
- // simple conversion
- // nvm, retarded conversion
- newNotes[i].sectionNotes.push({
- time: strumTime,
- data: noteData,
- length: holdLength,
- type: nType
- });
- }
- index++;
- }
- final events:Array = sortEvents(data.eventObjects);
- final newSong:Modern = {
- songName: data.songName,
- songId: StringTools.replace(data.song, " ", "-").toLowerCase(),
- audioFile: StringTools.replace(data.song, " ", "-").toLowerCase(),
- notes: newNotes,
+ public static function compat(data:Dynamic, ?name:String = null):ChartData
+ {
+ var songName:String = name ?? data.songId;
+ songName = songName.toTitleCase();
+ final songId:String = songName.toLowerKebabCase();
+ // retarded
+ var newSong:ChartData = {
+ songId: songId,
+ songName: songName,
+ audioFile: songId,
+ stage: data.stage,
+ notes: convertNotes(data),
player1: data.player1,
player2: data.player2,
gfVersion: data.gfVersion,
- stage: data.stage,
- bpm: data.bpm,
+ validScore: data.validScore,
speed: data.speed,
+ bpm: data.bpm,
+ eventObjects: [
+ {
+ name: 'Init BPM',
+ type: "BPM Change",
+ args: [data.bpm],
+ beat: 0
+ }
+ ],
+ chartVersion: Constants.chartVer,
needsVoices: data.needsVoices,
- style: data.style,
- eventObjects: events,
- splitVoiceTracks: data.splitVoiceTracks,
- chartVersion: Constants.chartVer
- };
- Song.recalculateAllSectionTimes(newSong);
- newNotes = null;
+ splitVoiceTracks: Paths.fileExists('songs/$songId/VoicesP.ogg'), // pisses me off a lot
+ style: "Default"
+ }
+ Paths.runGC();
return newSong;
}
- public static function convertKade(song:Dynamic):Modern
+ public static function convertNotes(song:Dynamic):Array
{
- final data:Legacy = cast song.song;
- data.eventObjects = checkEvents(data);
- data.eventObjects = convertEvents(data);
- var currentIndex = 0;
- var index = 0;
- var ba = song.bpm;
- if (data.audioFile == null)
- data.audioFile = StringTools.replace(data.song, " ", "-").toLowerCase();
- if (data.songId == null)
- data.songId = StringTools.replace(data.song, " ", "-").toLowerCase();
- if (data.songName == null)
- data.songName = data.song;
-
- if (data.noteStyle == 'pixel')
- data.style = "Pixel";
-
- if (data.style == null)
- data.style = "Default";
-
- if (data.gfVersion == null)
- data.gfVersion = "gf";
-
- if (data.stage == null)
- data.stage = "stage";
-
- if (data.splitVoiceTracks == null)
- data.splitVoiceTracks = false;
-
- // If the song has null sections.
- if (data.notes == null)
- {
- data.notes = [];
- data.notes.push(Song.oldSection(data));
- }
-
- // If the section array exists but there's nothing we push at least 1 section to play.
- if (data.notes.length == 0)
- data.notes.push(Song.oldSection(song));
+ final data:FNFKadeFormat = song;
var newNotes:Array = [];
+ var index = 0;
+ var currentIndex = 0;
TimingStruct.clearTimings();
for (i in data.eventObjects)
{
if (i.type == "BPM Change")
{
- var beat:Float = i.beat * Conductor.rate;
+ var beat:Float = i.position;
var endBeat:Float = Math.POSITIVE_INFINITY;
- TimingStruct.addTiming(beat, i.args[0] * Conductor.rate, endBeat, 0); // offset in this case = start time since we don't have a offset
+ TimingStruct.addTiming(beat, i.value, endBeat, 0); // offset in this case = start time since we don't have a offset
if (currentIndex != 0)
{
@@ -230,9 +144,9 @@ class ChartConverter
currentIndex++;
}
}
+
for (i => section in data.notes)
{
- section.index = i;
final currentBeat = 4 * index;
final currentSeg = TimingStruct.getTimingAtBeat(currentBeat);
newNotes.push({
@@ -241,55 +155,22 @@ class ChartConverter
bpm: currentSeg.bpm,
mustHitSection: section.mustHitSection,
lengthInSteps: 16,
- startTime: currentSeg.startTime,
+ startTime: section.startTime,
}); // create a blank for now
-
- if (section.lengthInSteps == null)
- section.lengthInSteps = 16;
-
- if (currentSeg == null)
- continue;
-
- final beat:Float = currentSeg.startBeat + (currentBeat - currentSeg.startBeat);
-
- if (section.changeBPM && section.bpm != ba)
- {
- ba = section.bpm;
- data.eventObjects.push({
- name: "FNF BPM Change " + section.index,
- beat: beat,
- args: [section.bpm],
- type: "BPM Change"
- });
- }
- section.mustHitSection = section.playerSec;
- var fard:Int = 0;
+ // vibrant:dad:0:#123123
for (ii in section.sectionNotes)
{
- // try not to brick the game challenge (impossible (thanks bolo))
if (section.mustHitSection)
- {
- var bool = false;
- if (ii[1] <= 3)
- {
- ii[1] += 4;
- bool = true;
- }
- if (ii[1] > 3)
- if (!bool)
- ii[1] -= 4;
- }
+ ii[1] = (ii[1] + 4) % 8;
+
+ if (ii[3] == null || ii[3] == 0)
+ ii[3] = "Normal";
final strumTime = ii[0];
final noteData = ii[1];
final holdLength = ii[2];
-
- if (ii[3] == null || !Std.isOfType(ii[3], String))
- ii[3] = 'Normal';
- var nType = ii[3];
-
- ii.resize(0);
+ final nType = ii[3];
// simple conversion
// nvm, retarded conversion
newNotes[i].sectionNotes.push({
@@ -301,185 +182,23 @@ class ChartConverter
}
index++;
}
- final events:Array = sortEvents(data.eventObjects);
- final newSong:Modern = {
- songName: data.songName,
- songId: data.songId,
- audioFile: data.audioFile,
- notes: newNotes,
- player1: data.player1,
- player2: data.player2,
- gfVersion: data.gfVersion,
- stage: data.stage,
- bpm: data.bpm,
- speed: data.speed,
- needsVoices: data.needsVoices,
- style: data.style,
- eventObjects: events,
- splitVoiceTracks: data.splitVoiceTracks,
- chartVersion: Constants.chartVer
- };
- Song.recalculateAllSectionTimes(newSong);
- newNotes = null;
- return newSong;
- }
-
- public static function convertPsychV1(song:Dynamic):Modern
- {
- final data:PsychFormat = cast song;
- var newEvents:Array = [];
- var newNotes:Array = [];
- var ba:Float = song.bpm;
- var structIndex:Int = 0;
- newEvents.push({
- name: "Init BPM",
- beat: 0,
- args: [ba],
- type: "BPM Change"
- });
- TimingStruct.addTiming(0, song.bpm * Conductor.rate, Math.POSITIVE_INFINITY, 0);
- // blank because the next breaks
- for (count => i in data.events)
- {
- newEvents.push({
- name: Std.string(i[0] + count),
- type: i[1][0],
- args: [i[1][1], i[1][2]],
- beat: TimingStruct.getBeatFromTime(i[0])
- });
- }
- for (i => section in data.notes)
- {
- final currentBeat = section.sectionBeats * i;
- final currentSeg = TimingStruct.getTimingAtBeat(currentBeat);
- final beat:Float = currentSeg.startBeat + (currentBeat - currentSeg.startBeat);
-
- if (section.changeBPM && section.bpm != ba)
- {
- ba = section.bpm;
- newEvents.push({
- name: "FNF BPM Change " + i,
- beat: beat,
- args: [section.bpm],
- type: "BPM Change"
- });
- }
-
- newNotes.push({
- index: i,
- sectionNotes: [],
- bpm: currentSeg.bpm,
- mustHitSection: section.mustHitSection,
- lengthInSteps: Std.int(section.sectionBeats * 4),
- startTime: 0
- }); // create a blank for now
- }
-
TimingStruct.clearTimings();
- for (i in newEvents)
- {
- if (i.type == "BPM Change")
- {
- var beat:Float = i.beat * Conductor.rate;
-
- var endBeat:Float = Math.POSITIVE_INFINITY;
-
- TimingStruct.addTiming(beat, i.args[0] * Conductor.rate, endBeat, 0); // offset in this case = start time since we don't have a offset
-
- if (structIndex != 0)
- {
- var data = TimingStruct.AllTimings[structIndex - 1];
- data.endBeat = beat;
- data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
- var step = ((60 / data.bpm) * 1000) / 4;
- TimingStruct.AllTimings[structIndex].startStep = Math.floor(((data.endBeat / (data.bpm / 60)) * 1000) / step);
- TimingStruct.AllTimings[structIndex].startTime = data.startTime + data.length;
- }
-
- structIndex++;
- }
- }
-
- for (i => section in data.notes)
- {
- final currentBeat = section.sectionBeats * i;
- final currentSeg = TimingStruct.getTimingAtBeat(currentBeat);
- newNotes[i].startTime = currentSeg.startTime;
- for (ii in section.sectionNotes)
- {
- // because psych flips them
- var bool = false;
- if (ii[1] <= 3)
- {
- ii[1] += 4;
- bool = true;
- }
- if (ii[1] > 3)
- if (!bool)
- ii[1] -= 4;
-
- if (ii[3] == null)
- ii[3] = "Normal";
-
- final strumTime = ii[0];
- final noteData = ii[1];
- final holdLength = ii[2];
- final nType = ii[3];
- newNotes[i].sectionNotes.push({
- time: strumTime,
- data: noteData,
- length: holdLength,
- type: nType
- });
- }
- }
-
- final events:Array = sortEvents(newEvents);
- final songName = StringTools.replace(data.song, " ", "-").toLowerCase();
- final newSong:Modern = {
- songName: data.song,
- songId: songName,
- audioFile: songName,
- notes: newNotes,
- player1: data.player1,
- player2: data.player2,
- gfVersion: data.gfVersion,
- stage: data.stage,
- bpm: data.bpm,
- speed: data.speed,
- needsVoices: data.needsVoices,
- style: 'Default', // doesn't exist anymore :/
- eventObjects: events,
- splitVoiceTracks: false,
- chartVersion: Constants.chartVer
- };
-
- Song.recalculateAllSectionTimes(newSong);
- newNotes = null;
- newEvents = null;
- return newSong;
+ return newNotes;
}
- public static function convertKEC2(song:Dynamic):Modern
+ // convert KEC1 to KEC2
+ public static function convertKEC1(song:Dynamic):ChartData
{
- final data:Legacy = cast song.song;
+ final data:KEC1Format = cast song.song;
+
data.eventObjects = convertEvents(data);
var newNotes:Array = [];
var index = 0;
var currentIndex = 0;
- // If the song has null sections.
- if (data.notes == null)
- {
- data.notes = [];
- data.notes.push(Song.oldSection(data));
- }
if (data.style == null)
data.style = "Default";
- // If the section array exists but there's nothing we push at least 1 section to play.
- if (data.notes.length == 0)
- data.notes.push(Song.oldSection(song));
TimingStruct.clearTimings();
for (i in data.eventObjects)
{
@@ -490,18 +209,16 @@ class ChartConverter
var endBeat:Float = Math.POSITIVE_INFINITY;
TimingStruct.addTiming(beat, Std.parseFloat(i.args[0]), endBeat, 0); // offset in this case = start time since we don't have a offset
-
if (currentIndex != 0)
{
var data = TimingStruct.AllTimings[currentIndex - 1];
data.endBeat = beat;
data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
var step = ((60 / data.bpm) * 1000) / 4;
+
TimingStruct.AllTimings[currentIndex].startStep = Math.floor(((data.endBeat / (data.bpm / 60)) * 1000) / step);
TimingStruct.AllTimings[currentIndex].startTime = data.startTime + data.length;
- Debug.logTrace(TimingStruct.AllTimings[currentIndex].startStep);
}
-
currentIndex++;
}
}
@@ -520,8 +237,6 @@ class ChartConverter
}); // create a blank for now
final beat:Float = currentSeg.startBeat + (currentBeat - currentSeg.startBeat);
section.mustHitSection = section.playerSec;
- if (Reflect.hasField(section, 'playerSec'))
- Reflect.deleteField(section, 'playerSec');
newNotes[i].index = i;
for (ii in section.sectionNotes)
{
@@ -533,7 +248,6 @@ class ChartConverter
ii.resize(0);
// simple conversion
// nvm, retarded conversion
-
newNotes[i].sectionNotes.push({
time: strumTime,
data: noteData,
@@ -543,7 +257,7 @@ class ChartConverter
}
index++;
}
- final newSong:Modern = {
+ final newSong:ChartData = {
songName: data.songName,
songId: data.songId,
audioFile: data.audioFile,
@@ -560,12 +274,12 @@ class ChartConverter
splitVoiceTracks: data.splitVoiceTracks,
chartVersion: Constants.chartVer
};
- Song.recalculateAllSectionTimes(newSong);
+ // Song.recalculateAllSectionTimes(newSong);
newNotes = null;
return newSong;
}
- private static function checkEvents(song:Legacy):Array
+ private static function checkEvents(song:KEC1Format):Array
{
if (song.eventObjects == null)
{
@@ -581,7 +295,7 @@ class ChartConverter
return song.eventObjects;
}
- private static function convertEvents(song:Legacy):Array
+ private static function convertEvents(song:KEC1Format):Array
{
var newEvents:Array = [];
for (i in song.eventObjects)
@@ -633,3 +347,37 @@ class ChartConverter
return arr;
}
}
+
+typedef KEC1Format =
+{
+ var songName:String;
+ var songId:String;
+ var ?song:String;
+ var chartVersion:String;
+ var notes:Array;
+ var eventObjects:Array;
+ var bpm:Float;
+ var needsVoices:Bool;
+ var speed:Float;
+ var player1:String;
+ var player2:String;
+ var gfVersion:String;
+ var ?noteStyle:String;
+ var style:String;
+ var stage:String;
+ var ?validScore:Bool;
+ var ?offset:Int;
+ var ?splitVoiceTracks:Bool;
+ var ?audioFile:String;
+}
+
+typedef KEC1Section =
+{
+ var sectionNotes:Array>;
+ var ?lengthInSteps:Null;
+ var mustHitSection:Bool;
+ var bpm:Float;
+ var changeBPM:Bool;
+ var ?index:Int;
+ var ?playerSec:Bool;
+}
diff --git a/source/kec/backend/chart/format/Modern.hx b/source/kec/backend/chart/ChartData.hx
similarity index 88%
rename from source/kec/backend/chart/format/Modern.hx
rename to source/kec/backend/chart/ChartData.hx
index adc42f64..4220bbcf 100644
--- a/source/kec/backend/chart/format/Modern.hx
+++ b/source/kec/backend/chart/ChartData.hx
@@ -1,6 +1,6 @@
-package kec.backend.chart.format;
+package kec.backend.chart;
-typedef Modern =
+typedef ChartData =
{
var songName:String;
var songId:String;
diff --git a/source/kec/backend/chart/format/Section.hx b/source/kec/backend/chart/Section.hx
similarity index 87%
rename from source/kec/backend/chart/format/Section.hx
rename to source/kec/backend/chart/Section.hx
index 828b10e7..f286019a 100644
--- a/source/kec/backend/chart/format/Section.hx
+++ b/source/kec/backend/chart/Section.hx
@@ -1,4 +1,4 @@
-package kec.backend.chart.format;
+package kec.backend.chart;
/**
* Old Section Shit For Conversion
diff --git a/source/kec/backend/chart/Song.hx b/source/kec/backend/chart/Song.hx
index 1825423a..9c328041 100644
--- a/source/kec/backend/chart/Song.hx
+++ b/source/kec/backend/chart/Song.hx
@@ -1,7 +1,5 @@
package kec.backend.chart;
-import kec.backend.chart.format.*;
-
typedef StyleData =
{
var style:String;
@@ -37,26 +35,13 @@ typedef SongMeta =
class Song
{
- public static function loadFromJsonRAW(rawJson:String)
- {
- while (!rawJson.endsWith("}"))
- {
- rawJson = rawJson.substr(0, rawJson.length - 1);
- // LOL GOING THROUGH THE BULLSHIT TO CLEAN IDK WHATS STRANGE
- }
-
- final jsonData = Json.parse(rawJson);
-
- return parseJSONshit('rawsong', jsonData, 'rawname');
- }
-
- public static function loadFromJson(songId:String, difficulty:String):Modern
+ public static function loadFromJson(songId:String, difficulty:String):ChartData
{
final songFile = 'data/songs/$songId/$songId$difficulty';
final rawJson = Paths.loadJSON(songFile);
- final metaData:SongMeta = loadMetadata(songId);
- doesChartExist(songId, difficulty);
- return parseJSONshit(songId, rawJson, metaData);
+ // final metaData:SongMeta = loadMetadata(songId);
+ // doesChartExist(songId, difficulty);
+ return parseJSON(rawJson, songId, difficulty);
}
public static function doesChartExist(songId:String, diff:String):Bool
@@ -81,43 +66,21 @@ class Song
return cast rawMetaJson;
}
- public static function conversionChecks(song:Dynamic):Modern
+ public static function conversionChecks(song:Dynamic, name:String, diff:String):ChartData
{
if (song?.chartVersion == Constants.chartVer)
return song;
- final oldFormat:Legacy = cast song.song;
-
- if (oldFormat.chartVersion != null)
- {
- switch (oldFormat.chartVersion)
- {
- case "KEC1":
- return ChartConverter.convertKEC2(song);
- default:
- return ChartConverter.convertKade(song);
- }
- }
- if (song.format == 'psych_v1_convert')
- {
- Debug.logTrace('${song.song} was a PSYCHKIGD chart');
- return ChartConverter.convertPsychV1(song);
- }
- else
- {
- Debug.logWarn("Your Chart Format Is Fucked.");
- return ChartConverter.convertEtc(song);
- }
- return song;
+ return ChartConverter.convert(song, name, diff);
}
- public static function parseJSONshit(songId:String, jsonData:Dynamic, jsonMetaData:Dynamic):Modern
+ public static function parseJSON(jsonData:Dynamic, name:String, diff:String):ChartData
{
final songData = cast jsonData;
- return Song.conversionChecks(songData);
+ return Song.conversionChecks(songData, name, diff);
}
- public static function checkforSections(SONG:Modern, songLength:Float)
+ public static function checkforSections(SONG:ChartData, songLength:Float)
{
var totalBeats = TimingStruct.getBeatFromTime(songLength);
@@ -125,14 +88,14 @@ class Song
while (lastSecBeat < totalBeats)
{
- SONG.notes.push(Song.newSection(SONG, SONG.notes[SONG.notes.length - 1].lengthInSteps, SONG.notes.length, true));
+ SONG.notes.push(newSection(SONG, SONG.notes[SONG.notes.length - 1].lengthInSteps, SONG.notes.length, true));
recalculateAllSectionTimes(SONG, SONG.notes.length - 1);
lastSecBeat = TimingStruct.getBeatFromTime(SONG.notes[SONG.notes.length - 1].endTime);
}
}
- public static function recalculateAllSectionTimes(activeSong:Modern, startIndex:Int = 0)
+ public static function recalculateAllSectionTimes(activeSong:ChartData, startIndex:Int = 0)
{
if (activeSong == null)
return;
@@ -159,7 +122,7 @@ class Song
}
}
- public static function newSection(song:Modern, lengthInSteps:Int = 16, index:Int = -1, mustHitSection:Bool = false):Section
+ public static function newSection(song:ChartData, lengthInSteps:Int = 16, index:Int = -1, mustHitSection:Bool = false):Section
{
var sec:Section = {
lengthInSteps: lengthInSteps,
@@ -171,18 +134,4 @@ class Song
return sec;
}
-
- public static function oldSection(song:Legacy, lengthInSteps:Int = 16, index:Int = -1, mustHitSection:Bool = false):LegacySection
- {
- var sec:LegacySection = {
- lengthInSteps: lengthInSteps,
- bpm: song.bpm,
- changeBPM: false,
- mustHitSection: mustHitSection,
- sectionNotes: [],
- index: index
- };
-
- return sec;
- }
}
diff --git a/source/kec/backend/chart/TimingStruct.hx b/source/kec/backend/chart/TimingStruct.hx
index 953162e8..ec396eec 100644
--- a/source/kec/backend/chart/TimingStruct.hx
+++ b/source/kec/backend/chart/TimingStruct.hx
@@ -1,6 +1,6 @@
package kec.backend.chart;
-import kec.backend.chart.format.Modern;
+import kec.backend.chart.ChartData;
/**
* Handy class that helps with beat and step measurements in song with variable bpm!
@@ -133,7 +133,7 @@ class TimingStruct
return time * 1000;
}
- public static function setSongTimings(song:Modern)
+ public static function setSongTimings(song:ChartData)
{
TimingStruct.clearTimings();
diff --git a/source/kec/backend/chart/format/Legacy.hx b/source/kec/backend/chart/format/Legacy.hx
deleted file mode 100644
index 3a2c0e5a..00000000
--- a/source/kec/backend/chart/format/Legacy.hx
+++ /dev/null
@@ -1,24 +0,0 @@
-package kec.backend.chart.format;
-
-typedef Legacy =
-{
- var songName:String;
- var songId:String;
- var ?song:String;
- var chartVersion:String;
- var notes:Array;
- var eventObjects:Array;
- var bpm:Float;
- var needsVoices:Bool;
- var speed:Float;
- var player1:String;
- var player2:String;
- var gfVersion:String;
- var ?noteStyle:String;
- var style:String;
- var stage:String;
- var ?validScore:Bool;
- var ?offset:Int;
- var ?splitVoiceTracks:Bool;
- var ?audioFile:String;
-}
diff --git a/source/kec/backend/chart/format/LegacySection.hx b/source/kec/backend/chart/format/LegacySection.hx
deleted file mode 100644
index 6faa31ac..00000000
--- a/source/kec/backend/chart/format/LegacySection.hx
+++ /dev/null
@@ -1,12 +0,0 @@
-package kec.backend.chart.format;
-
-typedef LegacySection =
-{
- var sectionNotes:Array>;
- var ?lengthInSteps:Null;
- var mustHitSection:Bool;
- var bpm:Float;
- var changeBPM:Bool;
- var ?index:Int;
- var ?playerSec:Bool;
-}
diff --git a/source/kec/backend/chart/format/PsychFormat.hx b/source/kec/backend/chart/format/PsychFormat.hx
deleted file mode 100644
index de12ced3..00000000
--- a/source/kec/backend/chart/format/PsychFormat.hx
+++ /dev/null
@@ -1,29 +0,0 @@
-package kec.backend.chart.format;
-
-typedef PsychFormat =
-{
- var song:String;
- var notes:Array;
- var events:Array;
- var bpm:Float;
- var needsVoices:Bool;
- var speed:Float;
- var offset:Float;
-
- var player1:String;
- var player2:String;
- var gfVersion:String;
- var stage:String;
- var format:String;
-}
-
-typedef PsychSection =
-{
- var sectionNotes:Array;
- var sectionBeats:Float;
- var mustHitSection:Bool;
- @:optional var altAnim:Bool;
- @:optional var gfSection:Bool;
- @:optional var bpm:Float;
- @:optional var changeBPM:Bool;
-}
diff --git a/source/kec/backend/lua/ModchartState.hx b/source/kec/backend/lua/ModchartState.hx
index aeeb282e..1c7e3375 100644
--- a/source/kec/backend/lua/ModchartState.hx
+++ b/source/kec/backend/lua/ModchartState.hx
@@ -344,11 +344,6 @@ class ModchartState
var path = Sys.getCwd() + "assets/data/songs/" + PlayState.SONG.songId + '/';
- #if FEATURE_STEPMANIA
- if (PlayState.isSM)
- path = PlayState.pathToSm + "/";
- #end
-
var data:BitmapData = BitmapData.fromFile(path + spritePath + ".png");
var sprite:FlxSprite = new FlxSprite(0, 0);
@@ -426,10 +421,6 @@ class ModchartState
}
var path = Paths.file('data/songs/${PlayState.SONG.songId}/modchart.lua');
- #if FEATURE_STEPMANIA
- if (PlayState.isSM)
- path = PlayState.pathToSm + "/modchart.lua";
- #end
var result = LuaL.dofile(lua, OpenFlAssets.getPath(path)); // execute le file
diff --git a/source/kec/backend/tools/ArraySortTools.hx b/source/kec/backend/tools/ArraySortTools.hx
new file mode 100644
index 00000000..d68ab64d
--- /dev/null
+++ b/source/kec/backend/tools/ArraySortTools.hx
@@ -0,0 +1,164 @@
+package kec.backend.tools;
+
+/**
+ * Contains code for sorting arrays using various algorithms.
+ * @see https://algs4.cs.princeton.edu/20sorting/
+ */
+class ArraySortTools
+{
+ /**
+ * Sorts the input array using the merge sort algorithm.
+ * Stable and guaranteed to run in linearithmic time `O(n log n)`,
+ * but less efficient in "best-case" situations.
+ *
+ * @param input The array to sort in-place.
+ * @param compare The comparison function to use.
+ */
+ public static function mergeSort(input:Array, compare:CompareFunction):Void
+ {
+ if (input == null || input.length <= 1)
+ return;
+ if (compare == null)
+ throw 'No comparison function provided.';
+
+ // Haxe implements merge sort by default.
+ haxe.ds.ArraySort.sort(input, compare);
+ }
+
+ /**
+ * Sorts the input array using the quick sort algorithm.
+ * More efficient on smaller arrays, but is inefficient `O(n^2)` in "worst-case" situations.
+ * Not stable; relative order of equal elements is not preserved.
+ *
+ * @see https://stackoverflow.com/questions/33884057/quick-sort-stackoverflow-error-for-large-arrays
+ * Fix for stack overflow issues.
+ * @param input The array to sort in-place.
+ * @param compare The comparison function to use.
+ */
+ public static function quickSort(input:Array, compare:CompareFunction):Void
+ {
+ if (input == null || input.length <= 1)
+ return;
+ if (compare == null)
+ throw 'No comparison function provided.';
+
+ quickSortInner(input, 0, input.length - 1, compare);
+ }
+
+ /**
+ * Internal recursive function for the quick sort algorithm.
+ * Written with ChatGPT!
+ */
+ static function quickSortInner(input:Array, low:Int, high:Int, compare:CompareFunction):Void
+ {
+ // When low == high, the array is empty or too small to sort.
+
+ // EDIT: Recurse on the smaller partition, and loop for the larger partition.
+ while (low < high)
+ {
+ // Designate the first element in the array as the pivot, then partition the array around it.
+ // Elements less than the pivot will be to the left, and elements greater than the pivot will be to the right.
+ // Return the index of the pivot.
+ var pivot:Int = quickSortPartition(input, low, high, compare);
+
+ if ((pivot) - low <= high - (pivot + 1))
+ {
+ quickSortInner(input, low, pivot, compare);
+ low = pivot + 1;
+ }
+ else
+ {
+ quickSortInner(input, pivot + 1, high, compare);
+ high = pivot;
+ }
+ }
+ }
+
+ /**
+ * Internal function for sorting a partition of an array in the quick sort algorithm.
+ * Written with ChatGPT!
+ */
+ static function quickSortPartition(input:Array, low:Int, high:Int, compare:CompareFunction):Int
+ {
+ // Designate the first element in the array as the pivot.
+ var pivot:T = input[low];
+ // Designate two pointers, used to divide the array into two partitions.
+ var i:Int = low - 1;
+ var j:Int = high + 1;
+
+ while (true)
+ {
+ // Move the left pointer to the right until it finds an element greater than the pivot.
+ do
+ {
+ i++;
+ }
+ while (compare(input[i], pivot) < 0);
+
+ // Move the right pointer to the left until it finds an element less than the pivot.
+ do
+ {
+ j--;
+ }
+ while (compare(input[j], pivot) > 0);
+
+ // If i and j have crossed, the array has been partitioned, and the pivot will be at the index j.
+ if (i >= j)
+ return j;
+
+ // Else, swap the elements at i and j, and start over.
+ // This slowly moves the pivot towards the middle of the partition,
+ // while moving elements less than the pivot to the left and elements greater than the pivot to the right.
+ var temp:T = input[i];
+ input[i] = input[j];
+ input[j] = temp;
+ }
+
+ // Don't expect to get here.
+ return -1;
+ }
+
+ /**
+ * Sorts the input array using the insertion sort algorithm.
+ * Stable and is very fast on nearly-sorted arrays,
+ * but is inefficient `O(n^2)` in "worst-case" situations.
+ *
+ * @param input The array to sort in-place.
+ * @param compare The comparison function to use.
+ */
+ public static function insertionSort(input:Array, compare:CompareFunction):Void
+ {
+ if (input == null || input.length <= 1)
+ return;
+ if (compare == null)
+ throw 'No comparison function provided.';
+
+ // Iterate through the array, starting at the second element.
+ for (i in 1...input.length)
+ {
+ // Store the current element.
+ var current:T = input[i];
+ // Store the index of the previous element.
+ var j:Int = i - 1;
+
+ // While the previous element is greater than the current element,
+ // move the previous element to the right and move the index to the left.
+ while (j >= 0 && compare(input[j], current) > 0)
+ {
+ input[j + 1] = input[j];
+ j--;
+ }
+
+ // Insert the current element into the array.
+ input[j + 1] = current;
+ }
+ }
+}
+
+/**
+ * A comparison function.
+ * Returns a negative number if the first argument is less than the second,
+ * a positive number if the first argument is greater than the second,
+ * or zero if the two arguments are equal.
+ */
+typedef CompareFunction = T->T->Int;
diff --git a/source/kec/backend/tools/ArrayTools.hx b/source/kec/backend/tools/ArrayTools.hx
new file mode 100644
index 00000000..926860c2
--- /dev/null
+++ b/source/kec/backend/tools/ArrayTools.hx
@@ -0,0 +1,106 @@
+package kec.backend.tools;
+
+/**
+ * A static extension which provides utility functions for Arrays.
+ */
+class ArrayTools
+{
+ /*
+ * Push an element to the array if it is not already present.
+ * @param input The array to push to
+ * @param element The element to push
+ * @return Whether the element was pushed
+ */
+ public static function pushUnique(input:Array, element:T):Bool
+ {
+ if (input.contains(element))
+ return false;
+ input.push(element);
+ return true;
+ }
+
+ /**
+ * Remove all elements from the array, without creating a new array.
+ * @param array The array to clear.
+ */
+ public static function clear(array:Array):Void
+ {
+ // This method is faster than array.splice(0, array.length)
+ while (array.length > 0)
+ array.pop();
+ }
+
+ /**
+ * Create a new array with all elements of the given array, to prevent modifying the original.
+ */
+ public static function clone(array:Array):Array
+ {
+ return [for (element in array) element];
+ }
+
+ /**
+ * Create a new array with clones of all elements of the given array, to prevent modifying the original.
+ */
+ public static function deepClone>(array:Array):Array
+ {
+ return [for (element in array) element.clone()];
+ }
+
+ /**
+ * Return true only if both arrays contain the same elements (possibly in a different order).
+ * @param a The first array to compare.
+ * @param b The second array to compare.
+ * @return Weather both arrays contain the same elements.
+ */
+ public static function isEqualUnordered(a:Array, b:Array):Bool
+ {
+ if (a.length != b.length)
+ return false;
+ for (element in a)
+ {
+ if (!b.contains(element))
+ return false;
+ }
+ for (element in b)
+ {
+ if (!a.contains(element))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if `superset` contains all elements of `subset`.
+ * @param superset The array to query for each element.
+ * @param subset The array containing the elements to query for.
+ * @return Weather `superset` contains all elements of `subset`.
+ */
+ public static function isSuperset(superset:Array, subset:Array):Bool
+ {
+ // Shortcuts.
+ if (subset.length == 0)
+ return true;
+ if (subset.length > superset.length)
+ return false;
+
+ // Check each element.
+ for (element in subset)
+ {
+ if (!superset.contains(element))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if `superset` contains all elements of `subset`.
+ * @param subset The array containing the elements to query for.
+ * @param superset The array to query for each element.
+ * @return Weather `superset` contains all elements of `subset`.
+ */
+ public static function isSubset(subset:Array, superset:Array):Bool
+ {
+ // Switch it around.
+ return isSuperset(superset, subset);
+ }
+}
diff --git a/source/kec/backend/tools/FloatTools.hx b/source/kec/backend/tools/FloatTools.hx
new file mode 100644
index 00000000..edb6577e
--- /dev/null
+++ b/source/kec/backend/tools/FloatTools.hx
@@ -0,0 +1,24 @@
+package kec.backend.tools;
+
+/**
+ * Utilities for performing common math operations.
+ */
+class FloatTools
+{
+ /**
+ * Constrain a float between a minimum and maximum value.
+ */
+ public static function clamp(value:Float, min:Float, max:Float):Float
+ {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ /**
+ Round a float to a certain number of decimal places.
+ **/
+ public static function round(number:Float, ?precision = 2):Float
+ {
+ number *= Math.pow(10, precision);
+ return Math.round(number) / Math.pow(10, precision);
+ }
+}
diff --git a/source/kec/backend/tools/ICloneable.hx b/source/kec/backend/tools/ICloneable.hx
new file mode 100644
index 00000000..fd917317
--- /dev/null
+++ b/source/kec/backend/tools/ICloneable.hx
@@ -0,0 +1,10 @@
+package kec.backend.tools;
+
+/**
+ * Implement this on a class to enable `Array.deepClone()` to work on it.
+ * NOTE: T should be the type of the class that implements this interface.
+ */
+interface ICloneable
+{
+ public function clone():T;
+}
diff --git a/source/kec/backend/tools/Int64Tools.hx b/source/kec/backend/tools/Int64Tools.hx
new file mode 100644
index 00000000..7aa0472b
--- /dev/null
+++ b/source/kec/backend/tools/Int64Tools.hx
@@ -0,0 +1,43 @@
+package kec.backend.tools;
+
+import haxe.Int64;
+
+/**
+ * Why `haxe.Int64` doesn't have a built-in `toFloat` function is beyond me.
+ */
+class Int64Tools
+{
+ private inline static var MAX_32_PRECISION:Float = 4294967296.0;
+
+ public static function fromFloat(f:Float):Int64
+ {
+ var h = Std.int(f / MAX_32_PRECISION);
+ var l = Std.int(f);
+ return Int64.make(h, l);
+ }
+
+ public static function toFloat(i:Int64):Float
+ {
+ var f:Float = i.low;
+ if (f < 0)
+ f += MAX_32_PRECISION;
+ return (i.high * MAX_32_PRECISION + f);
+ }
+
+ public static function isToIntSafe(i:Int64):Bool
+ {
+ return i.high != i.low >> 31;
+ }
+
+ public static function toIntSafe(i:Int64):Int
+ {
+ try
+ {
+ return Int64.toInt(i);
+ }
+ catch (e:Dynamic)
+ {
+ throw 'Could not represent value "${Int64.toStr(i)}" as an integer.';
+ }
+ }
+}
diff --git a/source/kec/backend/tools/IntTools.hx b/source/kec/backend/tools/IntTools.hx
new file mode 100644
index 00000000..32d5cf80
--- /dev/null
+++ b/source/kec/backend/tools/IntTools.hx
@@ -0,0 +1,16 @@
+package kec.backend.tools;
+
+/**
+ * Utilities for performing common math operations.
+ */
+class IntTools
+{
+ /**
+ * Constrain an integer between a minimum and maximum value.
+ */
+ public static function clamp(value:Int, min:Int, max:Int):Int
+ {
+ // Don't use Math.min because it returns a Float.
+ return value < min ? min : value > max ? max : value;
+ }
+}
diff --git a/source/kec/backend/tools/IteratorTools.hx b/source/kec/backend/tools/IteratorTools.hx
new file mode 100644
index 00000000..b5857206
--- /dev/null
+++ b/source/kec/backend/tools/IteratorTools.hx
@@ -0,0 +1,35 @@
+package kec.backend.tools;
+
+/**
+ * A static extension which provides utility functions for Iterators.
+ *
+ * For example, add `using IteratorTools` then call `iterator.array()`.
+ *
+ * @see https://haxe.org/manual/lf-static-extension.html
+ */
+class IteratorTools
+{
+ public static function array(iterator:Iterator):Array
+ {
+ return [for (i in iterator) i];
+ }
+
+ public static function count(iterator:Iterator, ?predicate:(item:T) -> Bool):Int
+ {
+ var n = 0;
+
+ if (predicate == null)
+ {
+ for (_ in iterator)
+ n++;
+ }
+ else
+ {
+ for (x in iterator)
+ if (predicate(x))
+ n++;
+ }
+
+ return n;
+ }
+}
diff --git a/source/kec/backend/tools/MapTools.hx b/source/kec/backend/tools/MapTools.hx
new file mode 100644
index 00000000..3489190e
--- /dev/null
+++ b/source/kec/backend/tools/MapTools.hx
@@ -0,0 +1,89 @@
+package kec.backend.tools;
+
+/**
+ * A static extension which provides utility functions for Maps.
+ *
+ * For example, add `using MapTools` then call `map.values()`.
+ *
+ * @see https://haxe.org/manual/lf-static-extension.html
+ */
+class MapTools
+{
+ /**
+ * Return the quantity of keys in the map.
+ */
+ public static function size(map:Map):Int
+ {
+ if (map == null)
+ return 0;
+ return map.keys().array().length;
+ }
+
+ /**
+ * Return a list of values from the map, as an array.
+ */
+ public static function values(map:Map):Array
+ {
+ if (map == null)
+ return [];
+ return [for (i in map.iterator()) i];
+ }
+
+ /**
+ * Create a new array with all elements of the given array, to prevent modifying the original.
+ */
+ public static function clone(map:Map):Map
+ {
+ if (map == null)
+ return null;
+ return map.copy();
+ }
+
+ /**
+ * Create a new map which is a combination of the two given maps.
+ * @param a The base map.
+ * @param b The other map. The values from this take precedence.
+ * @return The combined map.
+ */
+ public static function merge(a:Map, b:Map):Map
+ {
+ var result = a.copy();
+
+ for (pair in b.keyValueIterator())
+ {
+ result.set(pair.key, pair.value);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a new array with clones of all elements of the given array, to prevent modifying the original.
+ */
+ public static function deepClone>(map:Map):Map
+ {
+ // TODO: This function does NOT work.
+ throw "Not implemented";
+
+ /*
+ var newMap:Map = [];
+ // Replace each value with a clone of itself.
+ for (key in newMap.keys())
+ {
+ newMap.set(key, newMap.get(key).clone());
+ }
+ return newMap;
+ */
+ }
+
+ /**
+ * Return a list of keys from the map (as an array, rather than an iterator).
+ * TODO: Rename this?
+ */
+ public static function keyValues(map:Map):Array
+ {
+ if (map == null)
+ return [];
+ return map.keys().array();
+ }
+}
diff --git a/source/kec/backend/util/StringTool.hx b/source/kec/backend/tools/StringTools.hx
similarity index 98%
rename from source/kec/backend/util/StringTool.hx
rename to source/kec/backend/tools/StringTools.hx
index 760be777..7e194416 100644
--- a/source/kec/backend/util/StringTool.hx
+++ b/source/kec/backend/tools/StringTools.hx
@@ -1,6 +1,4 @@
-package kec.backend.util;
-
-// stolen from funkin
+package kec.backend.tools;
/**
* A static extension which provides utility functions for Strings.
diff --git a/source/kec/backend/util/DiffCalc.hx b/source/kec/backend/util/DiffCalc.hx
index 3f4d3bc9..2778a735 100644
--- a/source/kec/backend/util/DiffCalc.hx
+++ b/source/kec/backend/util/DiffCalc.hx
@@ -2,7 +2,7 @@ package kec.backend.util;
import openfl.system.System;
import flixel.math.FlxMath;
-import kec.backend.chart.format.Modern;
+import kec.backend.chart.ChartData;
class SmallNote // basically Note.hx but small as fuck
{
@@ -23,7 +23,7 @@ class DiffCalc
public static var lastDiffHandOne:Array = [];
public static var lastDiffHandTwo:Array = [];
- public static function CalculateDiff(song:Modern, opponentMode:Bool = false, ?accuracy:Float = .93)
+ public static function CalculateDiff(song:ChartData, opponentMode:Bool = false, ?accuracy:Float = .93)
{
// cleaned notes
var cleanedNotes:Array = [];
diff --git a/source/kec/backend/util/FileDialogHandler.hx b/source/kec/backend/util/FileDialogHandler.hx
new file mode 100644
index 00000000..d860b640
--- /dev/null
+++ b/source/kec/backend/util/FileDialogHandler.hx
@@ -0,0 +1,249 @@
+package kec.backend.util;
+
+import openfl.net.FileReference;
+import openfl.events.Event;
+import openfl.events.IOErrorEvent;
+import flash.net.FileFilter;
+import haxe.Exception;
+import sys.io.File;
+import lime.ui.*;
+import flixel.FlxBasic;
+
+// Currently only supports OPEN and SAVE, might change that in the future, who knows
+class FileDialogHandler extends FlxBasic
+{
+ var _fileRef:FileReferenceCustom;
+ var _dialogMode:FileDialogType = OPEN;
+
+ public function new()
+ {
+ _fileRef = new FileReferenceCustom();
+ _fileRef.addEventListener(Event.CANCEL, onCancelFn);
+ _fileRef.addEventListener(IOErrorEvent.IO_ERROR, onErrorFn);
+
+ super();
+ }
+
+ // callbacks
+ public var onComplete:Void->Void;
+ public var onCancel:Void->Void;
+ public var onError:Void->Void;
+
+ var _currentEvent:openfl.events.Event->Void;
+
+ public function save(?fileName:String = '', ?dataToSave:String = '', ?onComplete:Void->Void, ?onCancel:Void->Void, ?onError:Void->Void)
+ {
+ if (!completed)
+ {
+ throw new Exception('You must finish previous operation before starting a new one.');
+ }
+
+ this._dialogMode = SAVE;
+ _startUp(onComplete, onCancel, onError);
+
+ removeEvents();
+ _currentEvent = onSaveComplete;
+ _fileRef.addEventListener(#if desktop Event.SELECT #else Event.COMPLETE #end, _currentEvent);
+ _fileRef.save(dataToSave, fileName);
+ }
+
+ public function open(?defaultName:String = null, ?title:String = null, ?filter:Array = null, ?onComplete:Void->Void, ?onCancel:Void->Void,
+ ?onError:Void->Void)
+ {
+ if (!completed)
+ {
+ throw new Exception('You must finish previous operation before starting a new one.');
+ }
+
+ this._dialogMode = OPEN;
+ _startUp(onComplete, onCancel, onError);
+ if (filter == null)
+ filter = [new FileFilter('JSON', 'json')];
+
+ removeEvents();
+ _currentEvent = onLoadComplete;
+ _fileRef.addEventListener(#if desktop Event.SELECT #else Event.COMPLETE #end, _currentEvent);
+ _fileRef.browseEx(OPEN, defaultName, title, filter);
+ }
+
+ public function openDirectory(?title:String = null, ?onComplete:Void->Void, ?onCancel:Void->Void, ?onError:Void->Void)
+ {
+ if (!completed)
+ {
+ throw new Exception('You must finish previous operation before starting a new one.');
+ }
+
+ this._dialogMode = OPEN_DIRECTORY;
+ _startUp(onComplete, onCancel, onError);
+
+ removeEvents();
+ _currentEvent = onLoadDirectoryComplete;
+ _fileRef.addEventListener(#if desktop Event.SELECT #else Event.COMPLETE #end, _currentEvent);
+ _fileRef.browseEx(OPEN_DIRECTORY, null, title);
+ }
+
+ public var data:String;
+ public var path:String;
+ public var completed:Bool = true;
+
+ function onSaveComplete(_)
+ {
+ @:privateAccess
+ this.path = _fileRef._trackSavedPath;
+ this.completed = true;
+ trace('Saved file to: $path');
+
+ removeEvents();
+ this.completed = true;
+ if (onComplete != null)
+ onComplete();
+ }
+
+ function onLoadComplete(_)
+ {
+ @:privateAccess
+ this.path = _fileRef.__path;
+ this.data = File.getContent(this.path);
+ this.completed = true;
+ trace('Loaded file from: $path');
+
+ removeEvents();
+ this.completed = true;
+ if (onComplete != null)
+ onComplete();
+ }
+
+ function onLoadDirectoryComplete(_)
+ {
+ @:privateAccess
+ this.path = _fileRef.__path;
+ this.completed = true;
+ trace('Loaded directory: $path');
+
+ removeEvents();
+ this.completed = true;
+ if (onComplete != null)
+ onComplete();
+ }
+
+ function onCancelFn(_)
+ {
+ removeEvents();
+ this.completed = true;
+ if (onCancel != null)
+ onError();
+ }
+
+ function onErrorFn(_)
+ {
+ removeEvents();
+ this.completed = true;
+ if (onError != null)
+ onError();
+ }
+
+ function _startUp(onComplete:Void->Void, onCancel:Void->Void, onError:Void->Void)
+ {
+ this.onComplete = onComplete;
+ this.onCancel = onCancel;
+ this.onError = onError;
+ this.completed = false;
+
+ this.data = null;
+ this.path = null;
+ }
+
+ function removeEvents()
+ {
+ if (_currentEvent == null)
+ return;
+
+ _fileRef.removeEventListener(#if desktop Event.SELECT #else Event.COMPLETE #end, _currentEvent);
+ _currentEvent = null;
+ }
+
+ override function destroy()
+ {
+ removeEvents();
+ _fileRef = null;
+ _currentEvent = null;
+ onComplete = null;
+ onCancel = null;
+ onError = null;
+ data = null;
+ path = null;
+ completed = true;
+ super.destroy();
+ }
+}
+
+// Only way I could find to keep the path after saving a file
+class FileReferenceCustom extends FileReference
+{
+ @:allow(backend.FileDialogHandler)
+ var _trackSavedPath:String;
+
+ override function saveFileDialog_onSelect(path:String):Void
+ {
+ _trackSavedPath = path;
+ super.saveFileDialog_onSelect(path);
+ }
+
+ public function browseEx(browseType:FileDialogType = OPEN, ?defaultName:String, ?title:String = null, ?typeFilter:Array = null):Bool
+ {
+ __data = null;
+ __path = null;
+
+ #if desktop
+ var filter = null;
+
+ if (typeFilter != null)
+ {
+ var filters = [];
+
+ for (type in typeFilter)
+ {
+ filters.push(StringTools.replace(StringTools.replace(type.extension, "*.", ""), ";", ","));
+ }
+
+ filter = filters.join(";");
+ }
+
+ var openFileDialog = new FileDialog();
+ openFileDialog.onCancel.add(openFileDialog_onCancel);
+ openFileDialog.onSelect.add(openFileDialog_onSelect);
+ openFileDialog.browse(browseType, filter, defaultName, title);
+ return true;
+ #elseif (js && html5)
+ var filter = null;
+ if (typeFilter != null)
+ {
+ var filters = [];
+ for (type in typeFilter)
+ {
+ filters.push(StringTools.replace(StringTools.replace(type.extension, "*.", "."), ";", ","));
+ }
+ filter = filters.join(",");
+ }
+ if (filter != null)
+ {
+ __inputControl.setAttribute("accept", filter);
+ }
+ __inputControl.onchange = function()
+ {
+ var file = __inputControl.files[0];
+ modificationDate = Date.fromTime(file.lastModified);
+ creationDate = modificationDate;
+ size = file.size;
+ type = "." + Path.extension(file.name);
+ name = Path.withoutDirectory(file.name);
+ __path = file.name;
+ dispatchEvent(new Event(Event.SELECT));
+ }
+ __inputControl.click();
+ return true;
+ #end
+
+ return false;
+ }
+}
diff --git a/source/kec/backend/util/Paths.hx b/source/kec/backend/util/Paths.hx
index a8ad9678..4c10fd00 100644
--- a/source/kec/backend/util/Paths.hx
+++ b/source/kec/backend/util/Paths.hx
@@ -84,6 +84,14 @@ class Paths
return null;
}
+ inline static public function formatToSongPath(path:String)
+ {
+ final invalidChars = ~/[~&;:<>#\s]/g;
+ final hideChars = ~/[.,'"%?!]/g;
+
+ return hideChars.replace(invalidChars.replace(path, '-'), '').trim().toLowerCase();
+ }
+
public static inline function fileExists(key:String)
{
if (OpenFlAssets.exists(getPath(key)))
diff --git a/source/kec/backend/util/smTools/SMFile.hx b/source/kec/backend/util/smTools/SMFile.hx
deleted file mode 100644
index f895c481..00000000
--- a/source/kec/backend/util/smTools/SMFile.hx
+++ /dev/null
@@ -1,288 +0,0 @@
-#if FEATURE_STEPMANIA
-package kec.backend.util.smTools;
-
-import sys.io.File;
-import haxe.Exception;
-import lime.app.Application;
-import haxe.Json;
-import openfl.Lib;
-import kec.backend.chart.Song;
-import kec.backend.chart.TimingStruct;
-import kec.backend.chart.format.*;
-
-class SMFile
-{
- public static function loadFile(path):SMFile
- {
- var stepFile = new SMFile(File.getContent(path).split('\n'));
-
- return stepFile;
- }
-
- private var _fileData:Array;
-
- public var isDouble:Bool = false;
-
- public var isValid:Bool = true;
-
- public var _readTime:Float = 0;
-
- public var header:SMHeader;
- public var measures:Array;
-
- public var jsonPath:String = '';
-
- public function new(data:Array)
- {
- try
- {
- _fileData = data;
-
- // Gather header data
- var headerData = "";
- var inc = 0;
- while (!StringTools.contains(data[inc + 1], "//"))
- {
- headerData += data[inc];
- inc++;
- }
-
- header = new SMHeader(headerData.split(';'));
-
- if (_fileData.toString().split("#NOTES").length > 2)
- {
- Application.current.window.alert("The chart must only have 1 difficulty, this one has "
- + (_fileData.toString().split("#NOTES").length - 1),
- "SM File loading ("
- + header.TITLE
- + ")");
- isValid = false;
- return;
- }
-
- if (!StringTools.contains(header.MUSIC.toLowerCase(), "ogg"))
- {
- Application.current.window.alert("The music MUST be an OGG File, make sure the sm file has the right music property.",
- "SM File loading (" + header.TITLE + ")");
- isValid = false;
- return;
- }
-
- // check if this is a valid file, it should be a dance double file.
- inc += 3; // skip three lines down
- if (!StringTools.contains(data[inc], "dance-double:") && !StringTools.contains(data[inc], "dance-single"))
- {
- Application.current.window.alert("The file you are loading is neither a Dance Double chart or a Dance Single chart",
- "SM File loading (" + header.TITLE + ")");
- isValid = false;
- return;
- }
- if (StringTools.contains(data[inc], "dance-double:"))
- isDouble = true;
- inc += 5; // skip 5 down to where da notes @
-
- measures = [];
-
- var measure = "";
-
- for (ii in inc...data.length)
- {
- var i = data[ii];
- if (StringTools.contains(i, ",") || StringTools.contains(i, ";"))
- {
- measures.push(new SMMeasure(measure.split('\n')));
- measure = "";
- continue;
- }
- measure += i + "\n";
- }
- }
- catch (e:Exception)
- {
- Application.current.window.alert("Failure to load file.\n" + e, "SM File loading");
- }
- }
-
- public function convertToFNF(saveTo:String):String
- {
- // array's for helds
- var heldNotes:Array>;
-
- if (isDouble) // held storage lanes
- heldNotes = [[], [], [], [], [], [], [], []];
- else
- heldNotes = [[], [], [], []];
-
- // variables
-
- var measureIndex = 0;
- var currentBeat:Float = 0;
- var output = "";
-
- // init a fnf song
-
- var song:Modern = {
- songId: header.TITLE,
- songName: header.TITLE,
- audioFile: header.MUSIC,
- notes: [],
- eventObjects: [],
- bpm: header.getBPM(0),
- needsVoices: false,
- player1: 'bf',
- player2: 'gf',
- gfVersion: 'gf',
- style: 'Default',
- stage: 'stage',
- speed: 2.8,
- validScore: false,
- splitVoiceTracks: false,
- chartVersion: Constants.chartVer,
- };
-
- // lets check if the sm loading was valid
-
- if (!isValid)
- {
- final data:String = Json.stringify(song);
- File.saveContent(saveTo, data);
- return data;
- }
-
- // aight time to convert da measures
-
- for (measure in measures)
- {
- // private access since _measure is private
- @:privateAccess
- var lengthInRows = 192 / (measure._measure.length - 1);
-
- var rowIndex = 0;
-
- // section declaration
-
- var section:Section = {
- sectionNotes: [],
- lengthInSteps: 16,
- startTime: 0.0,
- endTime: 0.0,
- mustHitSection: false,
- bpm: header.getBPM(0),
- index: 0,
- };
-
- // if it's not a double always set this to true
-
- if (!isDouble)
- section.mustHitSection = true;
-
- @:privateAccess
- for (i in 0...measure._measure.length - 1)
- {
- var noteRow = (measureIndex * 192) + (lengthInRows * rowIndex);
- var notes:Array = [];
-
- for (note in measure._measure[i].split(''))
- {
- // output += note;
- notes.push(note);
- }
-
- currentBeat = noteRow / 48;
-
- if (currentBeat % 4 == 0)
- {
- // ok new section time
- song.notes.push(section);
- var section:Section = {
- sectionNotes: [],
- lengthInSteps: 16,
- startTime: 0.0,
- endTime: 0.0,
- mustHitSection: false,
- bpm: header.getBPM(0),
- index: rowIndex,
- };
- if (!isDouble)
- section.mustHitSection = true;
- }
-
- var seg = TimingStruct.getTimingAtBeat(currentBeat);
- var timeInSec:Float = (seg.startTime + ((currentBeat - seg.startBeat) / (seg.bpm / 60)));
- var rowTime = timeInSec * 1000;
- // output += " - Row " + noteRow + " - Time: " + rowTime + " (" + timeInSec + ") - Beat: " + currentBeat + " - Current BPM: " + header.getBPM(currentBeat) + "\n";
-
- var index = 0;
-
- for (i in notes)
- {
- // if its a mine lets skip (maybe add mines in the future??)
- var nType:String = "Normal";
- if (i == "M")
- nType = "Hurt";
-
- // get the lane and note type
- var lane = index + 4; // shitty fix
- var numba = Std.parseInt(i);
-
- // switch through the type and add the note
-
- switch (numba)
- {
- case 1: // normal
- section.sectionNotes.push({
- time: rowTime,
- data: lane,
- length: 0,
- type: nType
- });
- case 2: // held head
- heldNotes[lane] = [rowTime, lane, 0, rowTime];
- case 3: // held tail
- var data = heldNotes[lane];
- var timeDiff = rowTime - data[0];
- section.sectionNotes.push({
- time: data[0],
- data: lane,
- length: timeDiff,
- type: nType
- });
- heldNotes[index] = [];
- case 4: // roll head
- heldNotes[lane] = [rowTime, lane, 0, rowTime];
- }
- index++;
- }
-
- rowIndex++;
- }
-
- song.notes.push(section);
- measureIndex++;
- }
-
- for (i in 0...song.notes.length) // loops through sections
- {
- var section = song.notes[i];
- var currentBeat = 4 * i;
- var currentSeg = TimingStruct.getTimingAtBeat(currentBeat);
- var start:Float = (currentBeat - currentSeg.startBeat) / (currentSeg.bpm / 60);
- section.startTime = (currentSeg.startTime + start) * 1000;
-
- if (i != 0)
- song.notes[i - 1].endTime = section.startTime;
- section.endTime = Math.POSITIVE_INFINITY;
- }
-
- // File.saveContent("fuac" + header.TITLE,output);
-
- if (header.changeEvents.length != 0)
- song.eventObjects = header.changeEvents;
-
- song.chartVersion = Constants.chartVer;
- final data:String = Json.stringify(song);
- File.saveContent(saveTo, data);
- return data;
- }
-}
-#end
diff --git a/source/kec/backend/util/smTools/SMHeader.hx b/source/kec/backend/util/smTools/SMHeader.hx
deleted file mode 100644
index 3631c62b..00000000
--- a/source/kec/backend/util/smTools/SMHeader.hx
+++ /dev/null
@@ -1,120 +0,0 @@
-#if FEATURE_STEPMANIA
-package kec.backend.util.smTools;
-
-import kec.backend.chart.Song;
-import kec.backend.chart.Event;
-import kec.backend.chart.TimingStruct;
-
-class SMHeader
-{
- private var _header:Array;
-
- public var TITLE = "";
- public var SUBTITLE = "";
- public var ARTIST = "";
- public var GENRE = "";
- public var CREDIT = "";
- public var MUSIC = "";
- public var BANNER = "";
- public var BACKGROUND = "";
- public var CDTITLE = "";
- public var OFFSET = "";
- public var BPMS = ""; // time=bpm
-
- public var changeEvents:Array;
-
- public function new(headerData:Array)
- {
- _header = headerData;
-
- for (i in headerData)
- {
- readHeaderLine(i);
- }
-
- trace(BPMS);
-
- MUSIC = StringTools.replace(MUSIC, " ", "_");
-
- changeEvents = [];
-
- getBPM(0, true);
- }
-
- public function getBeatFromBPMIndex(index):Float
- {
- var bpmSplit = BPMS.split(',');
- var beat = 0;
- for (ii in 0...bpmSplit.length)
- {
- if (ii == index)
- return Std.parseFloat(StringTools.replace(bpmSplit[ii].split('=')[0], ",", ""));
- }
- return 0.0;
- }
-
- public function getBPM(beat:Float, printAllBpms:Bool = false)
- {
- var bpmSplit = BPMS.split(',');
- if (printAllBpms)
- {
- TimingStruct.clearTimings();
- var currentIndex = 0;
- for (i in bpmSplit)
- {
- var bpm:Float = Std.parseFloat(i.split('=')[1]);
- var beat:Float = Std.parseFloat(StringTools.replace(i.split('=')[0], ",", ""));
-
- var endBeat:Float = Math.POSITIVE_INFINITY;
-
- TimingStruct.addTiming(beat, bpm, endBeat, -Std.parseFloat(OFFSET));
-
- if (changeEvents.length != 0)
- {
- var data = TimingStruct.AllTimings[currentIndex - 1];
- data.endBeat = beat;
- data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
- var step = ((60 / data.bpm) * 1000) / 4;
- TimingStruct.AllTimings[currentIndex].startStep = Math.floor(((data.endBeat / (data.bpm / 60)) * 1000) / step);
- TimingStruct.AllTimings[currentIndex].startTime = data.startTime + data.length;
- }
-
- changeEvents.push({
- name: HelperFunctions.truncateFloat(beat, 0) + "SM",
- beat: beat,
- args: [bpm, 1],
- type: "BPM Change"
- });
-
- if (bpmSplit.length == 1)
- break;
- currentIndex++;
- }
-
- trace(changeEvents.length + " - BPM CHANGES");
- return 0.0;
- }
- var returningBPM = Std.parseFloat(bpmSplit[0].split('=')[1]);
- for (i in bpmSplit)
- {
- var bpm:Float = Std.parseFloat(i.split('=')[1]);
- var beatt:Float = Std.parseFloat(StringTools.replace(i.split('=')[0], ",", ""));
- if (beatt <= beat)
- returningBPM = bpm;
- }
- return returningBPM;
- }
-
- function readHeaderLine(line:String)
- {
- var propName = line.split('#')[1].split(':')[0];
- var value = line.split(':')[1].split(';')[0];
- var prop = Reflect.getProperty(this, propName);
-
- if (prop != null)
- {
- Reflect.setProperty(this, propName, value);
- }
- }
-}
-#end
diff --git a/source/kec/backend/util/smTools/SMMeasure.hx b/source/kec/backend/util/smTools/SMMeasure.hx
deleted file mode 100644
index 8d65f471..00000000
--- a/source/kec/backend/util/smTools/SMMeasure.hx
+++ /dev/null
@@ -1,29 +0,0 @@
-#if FEATURE_STEPMANIA
-package kec.backend.util.smTools;
-
-class SMMeasure
-{
- public var notes:Array;
-
- private var _measure:Array;
-
- public function new(measureData:Array)
- {
- _measure = measureData;
- notes = [];
-
- // 0 = no note
- // 1 = normal note
- // 2 = head of sustain
- // 3 = tail of sustain
-
- for (i in measureData)
- {
- for (ii in 0...i.length)
- {
- notes.push(new SMNote(i.split('')[ii], ii));
- }
- }
- }
-}
-#end
diff --git a/source/kec/backend/util/smTools/SMNote.hx b/source/kec/backend/util/smTools/SMNote.hx
deleted file mode 100644
index 5a73ac9f..00000000
--- a/source/kec/backend/util/smTools/SMNote.hx
+++ /dev/null
@@ -1,15 +0,0 @@
-#if FEATURE_STEPMANIA
-package kec.backend.util.smTools;
-
-class SMNote
-{
- public var data:String;
- public var lane:Int;
-
- public function new(_data:String, _lane:Int)
- {
- data = _data;
- lane = _lane;
- }
-}
-#end
diff --git a/source/kec/objects/Character.hx b/source/kec/objects/Character.hx
index 7df75191..e3a9b6ea 100644
--- a/source/kec/objects/Character.hx
+++ b/source/kec/objects/Character.hx
@@ -8,7 +8,7 @@ import kec.backend.chart.Song;
import kec.backend.chart.TimingStruct;
import kec.stages.TankmenBG;
import kec.backend.chart.ChartNote;
-import kec.backend.chart.format.Section;
+import kec.backend.chart.Section;
import kec.backend.character.CharacterData;
import kec.backend.character.AnimationData;
diff --git a/source/kec/objects/editor/EditorGrid.hx b/source/kec/objects/editor/EditorGrid.hx
index ca005f41..950f7a1f 100644
--- a/source/kec/objects/editor/EditorGrid.hx
+++ b/source/kec/objects/editor/EditorGrid.hx
@@ -10,7 +10,7 @@ class EditorGrid extends FlxSpriteGroup
public function new()
{
super(FlxG.width * 0.5 - ChartingState.gridSize * 4);
- var graphic = new FlxSprite().makeGraphic(Std.int(ChartingState.gridSize * 8) + ChartingState.separatorWidth, FlxG.height, FlxColor.fromRGB(0, 0, 0));
+ var graphic = new FlxSprite().makeGraphic(Std.int(ChartingState.gridSize * 8), FlxG.height, FlxColor.fromRGB(0, 0, 0));
grid = new FlxBackdrop(graphic.graphic, Y);
grid.alpha = 0.75;
add(grid);
diff --git a/source/kec/objects/note/Note.hx b/source/kec/objects/note/Note.hx
index c379e787..68cf9de7 100644
--- a/source/kec/objects/note/Note.hx
+++ b/source/kec/objects/note/Note.hx
@@ -11,7 +11,7 @@ class Note extends FlxSprite
{
public var strumTime:Float = 0;
public var baseStrum:Float = 0;
- public var lateHitMult:Float = 1.0;
+ public var lateHitMult:Float = 0.5;
public var earlyHitMult:Float = 1.0;
public var insideCharter:Bool = false;
@@ -72,7 +72,7 @@ class Note extends FlxSprite
public var isParent:Bool = false;
public var parent:Note = null;
public var spotInLine:Int = 0;
- public var sustainActive:Bool = false;
+ public var sustainActive(default, set):Bool = false;
public var children:Array = [];
@@ -202,7 +202,6 @@ class Note extends FlxSprite
this.prevNote = prevNote;
isSustainNote = sustainNote;
moves = false;
- lateHitMult = isSustainNote ? 0.5 : 1;
x += 50;
// MAKE SURE ITS DEFINITELY OFF SCREEN?
@@ -331,10 +330,7 @@ class Note extends FlxSprite
if (texture.length < 1)
{
- if (!PlayStateChangeables.opponentMode)
- skin = isPlayer ? Constants.noteskinSprite : Constants.cpuNoteskinSprite;
- else
- skin = isPlayer ? Constants.cpuNoteskinSprite : Constants.noteskinSprite;
+ skin = isPlayer ? Constants.noteskinSprite : Constants.cpuNoteskinSprite;
if (skin == null || skin.length < 1)
skin = isPlayer ? defaultPlayerSkin : defaultCpuSkin;
@@ -440,42 +436,36 @@ class Note extends FlxSprite
angle = modAngle;
}
- if (!insideCharter)
- {
- if (isSustainNote)
- {
- final newStepHeight = (((0.45 * PlayState.instance.fakeNoteStepCrochet)) * FlxMath.roundDecimal(PlayState.instance.scrollSpeed == 1 ? PlayState.SONG.speed : PlayState.instance.scrollSpeed,
- 2) * speedMultiplier);
-
- if (stepHeight != newStepHeight)
- {
- stepHeight = newStepHeight;
- if (isSustainNote)
- noteYOff = -stepHeight + swagWidth * 0.5;
- }
+ if (insideCharter)
+ return;
- flipY = PlayStateChangeables.useDownscroll;
- }
+ if (isSustainNote)
+ {
+ final newStepHeight = (((0.45 * PlayState.instance.fakeNoteStepCrochet)) * FlxMath.roundDecimal(PlayState.instance.scrollSpeed == 1 ? PlayState.SONG.speed : PlayState.instance.scrollSpeed,
+ 2) * speedMultiplier);
- if (mustPress)
+ if (stepHeight != newStepHeight)
{
- switch (noteType.toLowerCase())
- {
- case 'hurt':
- canBeHit = (strumTime - Conductor.elapsedPosition <= ((Ratings.timingWindows[0].timingWindow) * 0.2)
- && strumTime - Conductor.elapsedPosition >= (-Ratings.timingWindows[0].timingWindow) * 0.4);
- tooLate = (strumTime - Conductor.elapsedPosition < -Ratings.timingWindows[0].timingWindow && !wasGoodHit);
- default:
- canBeHit = (strumTime - Conductor.elapsedPosition <= (((Ratings.timingWindows[0].timingWindow) * lateHitMult))
- && strumTime - Conductor.elapsedPosition >= (((-Ratings.timingWindows[0].timingWindow) * earlyHitMult)));
- tooLate = (strumTime - Conductor.elapsedPosition < (-Ratings.timingWindows[0].timingWindow) && !wasGoodHit);
- }
+ stepHeight = newStepHeight;
+ if (isSustainNote)
+ noteYOff = -stepHeight + swagWidth * 0.5;
}
- if (tooLate && !wasGoodHit)
+ flipY = PlayStateChangeables.useDownscroll;
+ }
+
+ if (mustPress)
+ {
+ switch (noteType.toLowerCase())
{
- if (alpha > modAlpha * 0.3)
- alpha = modAlpha * 0.3;
+ case 'hurt':
+ canBeHit = (strumTime - Conductor.elapsedPosition <= ((Ratings.timingWindows[0].timingWindow) * 0.2)
+ && strumTime - Conductor.elapsedPosition >= (-Ratings.timingWindows[0].timingWindow) * 0.4);
+ tooLate = (strumTime - Conductor.elapsedPosition < -Ratings.timingWindows[0].timingWindow && !wasGoodHit);
+ default:
+ canBeHit = (strumTime - Conductor.elapsedPosition <= (((Ratings.timingWindows[0].timingWindow) * lateHitMult))
+ && strumTime - Conductor.elapsedPosition >= (((-Ratings.timingWindows[0].timingWindow) * earlyHitMult)));
+ tooLate = (strumTime - Conductor.elapsedPosition < (-Ratings.timingWindows[0].timingWindow) && !wasGoodHit);
}
}
}
@@ -567,6 +557,18 @@ class Note extends FlxSprite
swagRect.put();
}
+ function set_sustainActive(b:Bool)
+ {
+ sustainActive = b;
+ if (!b && !wasGoodHit)
+ {
+ Debug.logTrace("Too Late");
+ localAlpha = (localAlpha * 0.5);
+ }
+
+ return b;
+ }
+
function set_localAlpha(a:Float)
{
localAlpha = a;
diff --git a/source/kec/objects/note/NoteSplash.hx b/source/kec/objects/note/NoteSplash.hx
index 1b23ffdf..e4b39e9b 100644
--- a/source/kec/objects/note/NoteSplash.hx
+++ b/source/kec/objects/note/NoteSplash.hx
@@ -56,7 +56,7 @@ class NoteSplash extends FlxSprite
visible = true;
setPosition(x - Note.swagWidth * 0.95, y - Note.swagWidth);
- alpha = FlxG.save.data.alphaSplash;
+ alpha = note.alpha * FlxG.save.data.alphaSplash;
loadFrames(noteType);
offset.set(0, 0);
diff --git a/source/kec/objects/note/StaticArrow.hx b/source/kec/objects/note/StaticArrow.hx
index bf02b6cc..4eb0e27c 100644
--- a/source/kec/objects/note/StaticArrow.hx
+++ b/source/kec/objects/note/StaticArrow.hx
@@ -23,7 +23,6 @@ class StaticArrow extends FlxSprite
// Note Animation Suffixes.
private var dataSuffix:Array = ['LEFT', 'DOWN', 'UP', 'RIGHT'];
private var dataColor:Array = ['purple', 'blue', 'green', 'red'];
- private var player:Int;
private var lane:Int = 0;
public var resetAnim:Float = 0;
@@ -49,11 +48,10 @@ class StaticArrow extends FlxSprite
return value;
}
- public function new(xx:Float, yy:Float, ?player:Int, ?data:Int)
+ public function new(xx:Float, yy:Float, ?data:Int, ?isPlayer:Bool)
{
x = xx;
y = yy;
- this.player = player;
lane = data;
super(x, y);
direction = 90;
@@ -61,12 +59,9 @@ class StaticArrow extends FlxSprite
var skin:String = null;
if (texture.length < 1)
{
- if (player == 0)
- skin = Constants.cpuNoteskinSprite;
- else
- skin = Constants.noteskinSprite;
+ skin = isPlayer ? Constants.noteskinSprite : Constants.cpuNoteskinSprite;
if (skin == null || skin.length < 1)
- skin = player == 0 ? defaultPlayerSkin : defaultCpuSkin;
+ skin = isPlayer ? defaultPlayerSkin : defaultCpuSkin;
}
var customSkin:String = skin;
@@ -190,14 +185,14 @@ class StaticArrow extends FlxSprite
function set_localAlpha(value:Float)
{
localAlpha = value;
- alpha = localAlpha + modAlpha;
+ alpha = localAlpha * modAlpha;
return value;
}
function set_modAlpha(value:Float)
{
modAlpha = value;
- alpha = localAlpha + modAlpha;
+ alpha = localAlpha * modAlpha;
return value;
}
diff --git a/source/kec/objects/ui/HealthIcon.hx b/source/kec/objects/ui/HealthIcon.hx
index e7d1b34a..70ee7760 100644
--- a/source/kec/objects/ui/HealthIcon.hx
+++ b/source/kec/objects/ui/HealthIcon.hx
@@ -1,14 +1,12 @@
package kec.objects.ui;
-class HealthIcon extends FlxSprite
+class HealthIcon extends KECSprite
{
/**
* Used for FreeplayState! If you use it elsewhere, prob gonna annoying
*/
public var sprTracker:FlxSprite;
- public var animOffsets:Map>;
-
var char:String = '';
var isPlayer:Bool = false;
@@ -34,9 +32,6 @@ class HealthIcon extends FlxSprite
super();
this.isPlayer = isPlayer;
-
- animOffsets = new Map>();
-
changeIcon(char);
allowedToBop = FlxG.save.data.iconBop;
scrollFactor.set();
@@ -129,9 +124,6 @@ class HealthIcon extends FlxSprite
this.updateHitbox();
}
- public function addOffset(name:String, x:Float = 0, y:Float = 0)
- animOffsets[name] = [x, y];
-
inline function initTargetSize():Void
{
setGraphicSize(defaultSize);
@@ -205,9 +197,9 @@ class HealthIcon extends FlxSprite
if (!hasAnimation(newAnim) && !finishedAnim())
return;
this.animation.play(newAnim, false, false);
- var daOffset = animOffsets.get(newAnim);
+ final daOffset = offsets.get(newAnim);
- if (animOffsets.exists(newAnim))
+ if (offsets.exists(newAnim))
offset.set(daOffset[0], daOffset[1]);
else
offset.set(0, 0);
diff --git a/source/kec/states/FreeplayState.hx b/source/kec/states/FreeplayState.hx
index 565bd21b..5c5cd73a 100644
--- a/source/kec/states/FreeplayState.hx
+++ b/source/kec/states/FreeplayState.hx
@@ -11,10 +11,7 @@ import flixel.effects.FlxFlicker;
import sys.FileSystem;
import sys.io.File;
#end
-#if FEATURE_STEPMANIA
-import kec.backend.util.smTools.SMFile;
-#end
-import kec.backend.chart.format.Modern;
+import kec.backend.chart.ChartData;
import lime.app.Application;
import flash.text.TextField;
import openfl.utils.Assets as OpenFlAssets;
@@ -84,7 +81,7 @@ class FreeplayState extends MusicBeatState
public static var icon:HealthIcon;
- public var songData:Map> = [];
+ public var songData:Map> = [];
public static var instance:FreeplayState = null;
@@ -96,7 +93,7 @@ class FreeplayState extends MusicBeatState
public static var doUpdateText:Bool = true;
public static var alreadyPressed:Bool = false;
- function loadDiff(diff:Int, songId:String, array:Array)
+ function loadDiff(diff:Int, songId:String, array:Array)
array.push(Song.loadFromJson(songId, CoolUtil.getSuffixFromDiff(CoolUtil.difficulties[diff])));
public static var list:Array = [];
@@ -245,17 +242,6 @@ class FreeplayState extends MusicBeatState
intendedColor = bg.color;
lerpSelected = curSelected;
- PlayStateChangeables.modchart = FlxG.save.data.modcharts;
- PlayStateChangeables.botPlay = FlxG.save.data.botplay;
- PlayStateChangeables.opponentMode = FlxG.save.data.opponent;
- PlayStateChangeables.mirrorMode = FlxG.save.data.mirror;
- PlayStateChangeables.holds = FlxG.save.data.sustains;
- PlayStateChangeables.healthDrain = FlxG.save.data.hdrain;
- PlayStateChangeables.healthGain = FlxG.save.data.hgain;
- PlayStateChangeables.healthLoss = FlxG.save.data.hloss;
- PlayStateChangeables.practiceMode = FlxG.save.data.practice;
- PlayStateChangeables.skillIssue = FlxG.save.data.noMisses;
-
if (!Constants.freakyPlaying)
{
FlxG.sound.playMusic(Paths.music("freakyMenu"));
@@ -371,71 +357,6 @@ class FreeplayState extends MusicBeatState
meta.diffs = diffsThatExist;
songs.push(meta);
}
- #if FEATURE_STEPMANIA
- for (i in FileSystem.readDirectory("assets/sm/"))
- {
- if (FileSystem.isDirectory("assets/sm/" + i))
- {
- for (file in FileSystem.readDirectory("assets/sm/" + i))
- {
- if (file.contains(" "))
- FileSystem.rename("assets/sm/" + i + "/" + file, "assets/sm/" + i + "/" + file.replace(" ", "_"));
- if (file.endsWith(".sm") && !FileSystem.exists("assets/sm/" + i + "/converted.json"))
- {
- var file:SMFile = SMFile.loadFile("assets/sm/" + i + "/" + file.replace(" ", "_"));
- file.jsonPath = "assets/sm/" + i + "/converted.json";
- var data = file.convertToFNF("assets/sm/" + i + "/converted.json");
- var meta = new FreeplaySongMetadata(file.header.TITLE, 0, "sm", FlxColor.fromString("#9a9b9c"), file, "assets/sm/" + i);
- meta.diffs = ['Normal'];
- songs.push(meta);
- var song = Song.loadFromJsonRAW(data);
- instance.songData.set(file.header.TITLE, [song]);
-
- if (songData.get(song.songId) != null)
- {
- for (diff in songData.get(song.songId))
- {
- if (!songRating.exists(song.songId))
- songRating.set(Highscore.formatSong(song.songId, songData.get(song.songId)
- .indexOf(diff), 1), DiffCalc.CalculateDiff(song));
-
- if (!songRatingOp.exists(song.songId))
- songRatingOp.set(Highscore.formatSong(song.songId, songData.get(song.songId).indexOf(diff), 1),
- DiffCalc.CalculateDiff(song, true));
- }
- }
- }
- else if (FileSystem.exists("assets/sm/" + i + "/converted.json") && file.endsWith(".sm"))
- {
- var file:SMFile = SMFile.loadFile("assets/sm/" + i + "/" + file.replace(" ", "_"));
- file.jsonPath = "assets/sm/" + i + "/converted.json";
-
- file.convertToFNF("assets/sm/" + i + "/converted.json");
- var meta = new FreeplaySongMetadata(file.header.TITLE, 0, "sm", FlxColor.fromString("#9a9b9c"), file, "assets/sm/" + i);
- meta.diffs = ['Normal'];
- songs.push(meta);
- var song = Song.loadFromJsonRAW(File.getContent("assets/sm/" + i + "/converted.json"));
-
- instance.songData.set(file.header.TITLE, [song]);
-
- if (songData.get(song.songId) != null)
- {
- for (diff in songData.get(song.songId))
- {
- if (!songRating.exists(song.songId))
- songRating.set(Highscore.formatSong(song.songId, songData.get(song.songId)
- .indexOf(diff), 1), DiffCalc.CalculateDiff(song));
-
- if (!songRatingOp.exists(song.songId))
- songRatingOp.set(Highscore.formatSong(song.songId, songData.get(song.songId).indexOf(diff), 1),
- DiffCalc.CalculateDiff(song, true));
- }
- }
- }
- }
- }
- }
- #end
instance.songData.clear();
loadedSongData = true;
@@ -755,7 +676,7 @@ class FreeplayState extends MusicBeatState
super.update(elapsed);
}
- var playinSong:Modern;
+ var playinSong:ChartData;
private function dotheMusicThing():Void
{
@@ -803,15 +724,11 @@ class FreeplayState extends MusicBeatState
public static function loadSongInFreePlay(songName:String, difficulty:Int, isCharting:Bool, reloadSong:Bool = false)
{
// Make sure song data is initialized first.
- var currentSongData:Modern = null;
+ var currentSongData:ChartData = null;
try
{
switch (instance.songs[curSelected].songCharacter)
{
- #if FEATURE_STEPMANIA
- case "sm":
- currentSongData = Song.loadFromJsonRAW(#if FEATURE_FILESYSTEM File.getContent(instance.songs[curSelected].sm.jsonPath) #else OpenFlAssets.getText(instance.songs[curSelected].songName) #end);
- #end
default:
currentSongData = Song.loadFromJson(instance.songs[curSelected].songName,
CoolUtil.getSuffixFromDiff(CoolUtil.difficulties[CoolUtil.difficulties.indexOf(instance.songs[curSelected].diffs[difficulty])]));
@@ -830,18 +747,6 @@ class FreeplayState extends MusicBeatState
PlayState.isStoryMode = false;
// Debug.logInfo('Loading song ${PlayState.SONG.songId} from week ${PlayState.storyWeek} into Free Play...');
- #if FEATURE_STEPMANIA
- if (instance.songs[curSelected].songCharacter == "sm")
- {
- PlayState.isSM = true;
- PlayState.sm = instance.songs[curSelected].sm;
- PlayState.pathToSm = instance.songs[curSelected].path;
- }
- else
- PlayState.isSM = false;
- #else
- PlayState.isSM = false;
- #end
Conductor.rate = rate;
lastRate = rate;
@@ -1018,25 +923,10 @@ class FreeplaySongMetadata
{
public var songName:String = "";
public var week:Int = 0;
- #if FEATURE_STEPMANIA
- public var sm:SMFile;
- public var path:String;
- #end
public var songCharacter:String = "";
public var color:Int = -7179779;
public var diffs = [];
- #if FEATURE_STEPMANIA
- public function new(song:String, week:Int, songCharacter:String, ?color:FlxColor, ?sm:SMFile = null, ?path:String = "")
- {
- this.songName = song;
- this.week = week;
- this.songCharacter = songCharacter;
- this.color = color;
- this.sm = sm;
- this.path = path;
- }
- #else
public function new(song:String, week:Int, songCharacter:String, ?color:FlxColor)
{
this.songName = song;
@@ -1044,5 +934,4 @@ class FreeplaySongMetadata
this.songCharacter = songCharacter;
this.color = color;
}
- #end
}
diff --git a/source/kec/states/GameplayCustomizeState.hx b/source/kec/states/GameplayCustomizeState.hx
index dce9394a..e535438d 100644
--- a/source/kec/states/GameplayCustomizeState.hx
+++ b/source/kec/states/GameplayCustomizeState.hx
@@ -27,11 +27,8 @@ class GameplayCustomizeState extends UIState
public static var instance:GameplayCustomizeState = null;
- var laneunderlay:FlxSprite;
- var laneunderlayOpponent:FlxSprite;
-
var strumLine:FlxSprite;
- var strumLineNotes:FlxTypedGroup;
+ var strumLineNotes:FlxTypedGroup;
var camPos:FlxPoint;
@@ -82,7 +79,7 @@ class GameplayCustomizeState extends UIState
Stage.inEditor = true;
Stage.loadStageData('stage');
Stage.initStageProperties();
-
+
camHUD = new FlxCamera();
camHUD.bgColor.alpha = 0;
@@ -176,11 +173,11 @@ class GameplayCustomizeState extends UIState
if (FlxG.save.data.downscroll)
strumLine.y = FlxG.height - 165;
- strumLineNotes = new FlxTypedGroup();
+ strumLineNotes = new FlxTypedGroup();
add(strumLineNotes);
- generateStaticArrows(0);
- generateStaticArrows(1);
+ generateStaticArrows();
+ appearStaticArrows();
text = new FlxText(5, FlxG.height + 40, 0,
"Click and drag around gameplay elements to customize their positions. Press R to reset. Q/E to change zoom. Press Escape to go back.", 12);
@@ -320,49 +317,63 @@ class GameplayCustomizeState extends UIState
// ripped from play state cuz im lazy
- private function generateStaticArrows(player:Int, ?tween:Bool = true):Void
+ private function generateStaticArrows():Void
{
- final seX:Float = !PlayStateChangeables.opponentMode ? (PlayStateChangeables.middleScroll ? -278 : 42) : (PlayStateChangeables.middleScroll ? 366 : 42);
+ final seX:Float = (PlayStateChangeables.middleScroll ? -278 : 42);
final seY:Float = strumLine.y;
- for (i in 0...4)
+ for (i in 0...8)
{
- var babyArrow:StaticArrow = new StaticArrow(seX, seY, player, i);
-
- var noteTypeCheck:String = 'normal';
+ final isPlayer:Bool = i > 3;
+ final id:Int = i % 4;
+ var babyArrow:StaticArrow = new StaticArrow(seX, seY, id, isPlayer);
babyArrow.downScroll = PlayStateChangeables.useDownscroll;
+ babyArrow.alpha = 0;
+ babyArrow.ID = i;
- babyArrow.x += Note.swagWidth * i;
-
- var targAlpha = 1;
-
- if (PlayStateChangeables.middleScroll)
+ if (!isPlayer)
{
- if (PlayStateChangeables.opponentMode)
+ if (PlayStateChangeables.middleScroll)
{
- if (player == 1)
- targAlpha = 0;
+ babyArrow.x += 310;
+ if (i > 1)
+ { // Up and Right
+ babyArrow.x += FlxG.width / 2 + 25;
+ }
}
- else
- {
- if (player == 0)
- targAlpha = 0;
- }
- }
-
- if (tween)
- {
- babyArrow.y -= 10;
- babyArrow.alpha = 0;
- createTween(babyArrow, {y: babyArrow.y + 10, alpha: targAlpha}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * i)});
}
- else
- babyArrow.alpha = targAlpha;
- babyArrow.ID = i;
+ babyArrow.x += Note.swagWidth * id;
babyArrow.x += 50;
- babyArrow.x += ((FlxG.width * 0.5) * player);
+ babyArrow.x += ((FlxG.width / 2) * (isPlayer ? 1 : 0));
strumLineNotes.add(babyArrow);
}
}
+
+ private function appearStaticArrows(t:Bool = true):Void
+ {
+ var index:Int = 0;
+ strumLineNotes.forEachAlive(function(n:StaticArrow)
+ {
+ var targetAlpha:Float = 1;
+ if (index < 4)
+ {
+ if (PlayStateChangeables.middleScroll)
+ targetAlpha = 0.35;
+ }
+
+ if (t)
+ {
+ n.y -= 10;
+ n.modAlpha = 0;
+ createTween(n, {y: n.y + 10, modAlpha: targetAlpha}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * index % 4)});
+ }
+ else
+ {
+ n.modAlpha = targetAlpha;
+ }
+
+ index++;
+ });
+ }
}
diff --git a/source/kec/states/MainMenuState.hx b/source/kec/states/MainMenuState.hx
index d2f8f3a0..4a792fb5 100644
--- a/source/kec/states/MainMenuState.hx
+++ b/source/kec/states/MainMenuState.hx
@@ -166,7 +166,6 @@ class MainMenuState extends MusicBeatState
PlayState.storyDifficulty = 1;
PlayState.SONG = Song.loadFromJson('salvation', '');
PlayState.isStoryMode = false;
- PlayState.isSM = false;
MusicBeatState.switchState(new PlayState());
}
diff --git a/source/kec/states/MusicBeatState.hx b/source/kec/states/MusicBeatState.hx
index 145bc012..a9b91051 100644
--- a/source/kec/states/MusicBeatState.hx
+++ b/source/kec/states/MusicBeatState.hx
@@ -1,11 +1,11 @@
package kec.states;
-import kec.backend.chart.format.Section;
+import kec.backend.chart.Section;
import flixel.addons.transition.FlxTransitionableState;
import kec.backend.Controls;
import kec.backend.PlayerSettings;
import kec.backend.chart.TimingStruct;
-import kec.backend.chart.format.Modern;
+import kec.backend.chart.ChartData;
import kec.states.FreeplayState;
import kec.substates.CustomFadeTransition;
import kec.substates.MusicBeatSubstate;
@@ -18,7 +18,7 @@ class MusicBeatState extends FlxState implements IMusicBeatObject
private var curSection(default, set):Int = 0;
var step = 0.0;
var startInMS = 0.0;
- var activeSong:Modern = null;
+ var activeSong:ChartData = null;
private var currentSection:Section = null;
diff --git a/source/kec/states/PlayState.hx b/source/kec/states/PlayState.hx
index 65371187..f28cfd75 100644
--- a/source/kec/states/PlayState.hx
+++ b/source/kec/states/PlayState.hx
@@ -1,29 +1,31 @@
package kec.states;
-import haxe.ds.StringMap;
import flixel.addons.effects.FlxTrail;
import flixel.addons.transition.FlxTransitionableState;
import flixel.graphics.FlxGraphic;
import flixel.math.FlxRect;
import flixel.ui.FlxBar;
import flixel.util.FlxSort;
+import haxe.ds.StringMap;
import kec.backend.HitSounds;
import kec.backend.PlayStateChangeables;
import kec.backend.PlayerSettings;
import kec.backend.Ratings.RatingWindow;
import kec.backend.Ratings;
import kec.backend.Stats;
+import kec.backend.chart.ChartData;
import kec.backend.chart.ChartNote;
import kec.backend.chart.Event;
+import kec.backend.chart.Section;
import kec.backend.chart.Song.StyleData;
import kec.backend.chart.Song;
import kec.backend.chart.TimingStruct;
-import kec.backend.chart.format.Modern;
import kec.backend.util.HelperFunctions;
import kec.backend.util.Highscore;
import kec.backend.util.NoteStyleHelper;
import kec.backend.util.Sort;
import kec.objects.Alphabet;
+import kec.objects.Bar;
import kec.objects.Character;
import kec.objects.note.Note;
import kec.objects.note.NoteSplash;
@@ -46,11 +48,6 @@ import openfl.Lib;
import openfl.events.KeyboardEvent;
import openfl.media.Sound;
import openfl.utils.Assets as OpenFlAssets;
-import kec.objects.Bar;
-import kec.backend.chart.format.Section;
-#if FEATURE_STEPMANIA
-import kec.backend.util.smTools.SMFile;
-#end
#if FEATURE_LUAMODCHART
import kec.backend.lua.LuaClass;
import kec.backend.lua.ModchartState;
@@ -94,7 +91,7 @@ class PlayState extends MusicBeatState
// I shit my pants
// Song Data. Very Useful Uses Like SONG.songId Or Some Shit.
- public static var SONG:Modern;
+ public static var SONG:ChartData;
// Style Data. Like Pixel Or Default Or Something. Controls The UI Basically.
public static var STYLE:StyleData;
@@ -184,13 +181,6 @@ class PlayState extends MusicBeatState
public static var vocalsEnemy:FlxSound;
public static var inst:FlxSound;
- // Stepmania Variables.
- public static var isSM:Bool = false;
- public static var pathToSm:String;
- #if FEATURE_STEPMANIA
- public static var sm:SMFile;
- #end
-
// Notesplashes
private var grpNoteSplashes:FlxTypedGroup;
@@ -378,8 +368,6 @@ class PlayState extends MusicBeatState
// Search For Lua Modcharts
#if (FEATURE_FILESYSTEM && FEATURE_LUAMODCHART)
executeModchart = OpenFlAssets.exists(Paths.lua('songs/${PlayState.SONG.songId}/modchart')) && PlayStateChangeables.modchart;
- if (isSM)
- executeModchart = OpenFlAssets.exists(pathToSm + "/modchart.lua");
#end
#if !FEATURE_LUAMODCHART
executeModchart = false;
@@ -694,9 +682,7 @@ class PlayState extends MusicBeatState
tweenBoolshit = SONG.songId != 'tutorial' && SONG.songId != 'roses';
- generateStaticArrows(0);
- generateStaticArrows(1);
-
+ generateStaticArrows();
appearStaticArrows(tweenBoolshit);
// If A Song Doesn't Have Events, It Makes One Automatically.
@@ -726,10 +712,7 @@ class PlayState extends MusicBeatState
#if FEATURE_DISCORD
// Making difficulty text for Discord Rich Presence.
- if (!isSM)
- storyDifficultyText = CoolUtil.difficultyFromInt(storyDifficulty);
- else
- storyDifficultyText = "SM";
+ storyDifficultyText = CoolUtil.difficultyFromInt(storyDifficulty);
iconRPC = SONG.player2;
// To avoid having duplicate images in Discord assets
@@ -1028,10 +1011,7 @@ class PlayState extends MusicBeatState
{
healthBar = new Bar(0, 0, 'healthBar', function() return shownHealth, 0, 2);
healthBar.screenCenter(X);
- if (!PlayStateChangeables.opponentMode)
- healthBar.goesToRight = false;
- else
- healthBar.goesToRight = true;
+ healthBar.goesToRight = false;
if (FlxG.save.data.healthBar)
uiGroup.add(healthBar);
@@ -1195,7 +1175,7 @@ class PlayState extends MusicBeatState
#end
inCutscene = false;
-
+
if (!arrowsShown)
appearStaticArrows(true);
@@ -1466,23 +1446,6 @@ class PlayState extends MusicBeatState
b.dance();
}
}
-
- if (PlayStateChangeables.opponentMode)
- {
- for (d in dadGroup.members)
- {
- if (d.holdTimer > Conductor.stepCrochet * 4 * 0.001 * d.data.holdLength * 0.5)
- {
- if (d.animation.curAnim.name.startsWith('sing')
-
- && !d.animation.curAnim.name.endsWith('miss')
- && (d.animation.curAnim.curFrame >= 10 || d.animation.curAnim.finished))
- {
- d.dance();
- }
- }
- }
- }
}
// sadly stolen from Psych. Im sorry :(((
@@ -1510,8 +1473,6 @@ class PlayState extends MusicBeatState
Stats.totalPlayed += 1;
var char:Character = boyfriend;
- if (PlayStateChangeables.opponentMode)
- char = dad;
if (char.offsets.exists(Constants.singAnimations[direction] + 'miss'))
char.playAnim(Constants.singAnimations[direction] + 'miss', true);
@@ -1581,7 +1542,7 @@ class PlayState extends MusicBeatState
for (d in dadGroup.members)
{
- if (idleToBeat && !d.animation.curAnim.name.startsWith("sing") && !PlayStateChangeables.opponentMode)
+ if (idleToBeat && !d.animation.curAnim.name.startsWith("sing"))
d.dance(forcedToIdle);
}
@@ -1699,17 +1660,7 @@ class PlayState extends MusicBeatState
}
}
- if (!isStoryMode && isSM)
- {
- #if FEATURE_STEPMANIA
- var bytes = File.getBytes(pathToSm + "/" + sm.header.MUSIC);
- var sound = new Sound();
- sound.loadCompressedDataFromByteArray(bytes.getData(), bytes.length);
- inst = new FlxSound().loadEmbedded(sound);
- #end
- }
- else
- inst = new FlxSound().loadEmbedded(Paths.inst(PlayState.SONG.audioFile));
+ inst = new FlxSound().loadEmbedded(Paths.inst(PlayState.SONG.audioFile));
initEvents();
inst.play();
@@ -1761,9 +1712,6 @@ class PlayState extends MusicBeatState
if (Math.isNaN(holdLength))
holdLength = 0.0;
- if (PlayStateChangeables.opponentMode)
- playerNote = !playerNote;
-
var oldNote:Note;
if (unspawnNotes.length > 0)
oldNote = unspawnNotes[unspawnNotes.length - 1];
@@ -1848,37 +1796,39 @@ class PlayState extends MusicBeatState
}
}
- private function generateStaticArrows(player:Int):Void
+ private function generateStaticArrows():Void
{
- final seX:Float = !PlayStateChangeables.opponentMode ? (PlayStateChangeables.middleScroll ? -278 : 42) : (PlayStateChangeables.middleScroll ? 366 : 42);
+ final seX:Float = (PlayStateChangeables.middleScroll ? -278 : 42);
final seY:Float = strumLine.y;
- for (i in 0...4)
+ for (i in 0...8)
{
- var babyArrow:StaticArrow = new StaticArrow(seX, seY, player, i);
-
- var noteTypeCheck:String = 'normal';
+ final isPlayer:Bool = i > 3;
+ final id:Int = i % 4;
+ var babyArrow:StaticArrow = new StaticArrow(seX, seY, id, isPlayer);
babyArrow.downScroll = PlayStateChangeables.useDownscroll;
- babyArrow.x += Note.swagWidth * i;
babyArrow.alpha = 0;
babyArrow.ID = i;
babyArrow.loadLane();
arrowLanes.add(babyArrow.bgLane);
- switch (player)
+ if (isPlayer)
+ playerStrums.add(babyArrow);
+ else
{
- case 0:
- if (!PlayStateChangeables.opponentMode)
- cpuStrums.add(babyArrow);
- else
- playerStrums.add(babyArrow);
- case 1:
- if (!PlayStateChangeables.opponentMode)
- playerStrums.add(babyArrow);
- else
- cpuStrums.add(babyArrow);
+ if (PlayStateChangeables.middleScroll)
+ {
+ babyArrow.x += 310;
+ if (i > 1)
+ { // Up and Right
+ babyArrow.x += FlxG.width / 2 + 25;
+ }
+ }
+ cpuStrums.add(babyArrow);
}
+
+ babyArrow.x += Note.swagWidth * id;
babyArrow.x += 50;
- babyArrow.x += ((FlxG.width * 0.5) * player);
+ babyArrow.x += ((FlxG.width / 2) * (isPlayer ? 1 : 0));
strumLineNotes.add(babyArrow);
}
@@ -1891,29 +1841,24 @@ class PlayState extends MusicBeatState
var index:Int = 0;
strumLineNotes.forEachAlive(function(n:StaticArrow)
{
- var targAlpha = 1;
-
- if (PlayStateChangeables.middleScroll)
+ var targetAlpha:Float = 1;
+ if (index < 4)
{
- if (PlayStateChangeables.opponentMode)
- {
- if (index < 3)
- targAlpha = 0;
- }
- else
- {
- if (index > 4)
- targAlpha = 0;
- }
+ if (PlayStateChangeables.middleScroll)
+ targetAlpha = 0.35;
}
+
if (t)
{
n.y -= 10;
- n.alpha = 0;
- createTween(n, {y: n.y + 10, alpha: targAlpha}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * index % 4)});
+ n.modAlpha = 0;
+ createTween(n, {y: n.y + 10, modAlpha: targetAlpha}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * index % 4)});
}
else
- n.alpha = targAlpha;
+ {
+ n.modAlpha = targetAlpha;
+ n.bgLane.alpha = FlxG.save.data.laneTransparency * n.modAlpha;
+ }
index++;
});
@@ -2016,33 +1961,13 @@ class PlayState extends MusicBeatState
override public function update(elapsed:Float)
{
- if (startedCountdown)
- {
- Conductor.elapsedPosition += FlxG.elapsed * 1000;
-
- if (Conductor.elapsedPosition > 0 && startingSong)
- startSong();
-
- if (songStarted && !endingSong && (inst.length / Conductor.rate) - Conductor.elapsedPosition <= 0)
- endSong();
- Conductor.songPosition = Conductor.elapsedPosition * Conductor.rate;
- final curTime:Float = Math.max(0, Conductor.songPosition) / Conductor.rate;
- songPositionBar = CoolUtil.fpsLerp(songPositionBar, (curTime / songLength), 0.15, 60 * Conductor.rate);
- final songCalc:Float = (songLength - curTime);
- var secondsTotal:Int = Math.floor(songCalc * 0.001);
- if (secondsTotal < 0)
- secondsTotal = 0;
- songName.text = SONG.songName + ' (' + FlxStringUtil.formatTime(secondsTotal, false) + ')';
- checkMusicSync();
- }
-
+ setConductorTime();
if (unspawnNotes[0] != null)
{
var shit:Float = 2000;
if (SONG.speed < 1 || scrollSpeed < 1)
shit /= scrollSpeed == 1 ? SONG.speed : scrollSpeed;
var time:Float = shit * Conductor.rate;
-
while (unspawnNotes.length > 0 && unspawnNotes[0].strumTime - Conductor.elapsedPosition < time)
{
var dunceNote:Note = unspawnNotes[0];
@@ -2116,7 +2041,7 @@ class PlayState extends MusicBeatState
// all notes should be kept in the correct order and this is optimal, safe to do every frame/update
if (notesHitArray.length > 0)
{
- var data = Date.now().getTime();
+ final data = Date.now().getTime();
var balls = notesHitArray.length - 1;
while (balls >= 0)
{
@@ -2312,16 +2237,9 @@ class PlayState extends MusicBeatState
shownHealth = CoolUtil.fpsLerp(shownHealth, health, 0.15, 60 * Conductor.rate);
else
shownHealth = health;
- if (!PlayStateChangeables.opponentMode)
- {
- iconP1.updateHealthIcon(health);
- iconP2.updateHealthIcon(2 - health);
- }
- else
- {
- iconP1.updateHealthIcon(2 - health);
- iconP2.updateHealthIcon(health);
- }
+
+ iconP1.updateHealthIcon(health);
+ iconP2.updateHealthIcon(2 - health);
// Camera Related Stuff.
@@ -2353,7 +2271,7 @@ class PlayState extends MusicBeatState
return;
}
- final strum:StaticArrow = strumLineNotes.members[daNote.rawNoteData];
+ final strum:StaticArrow = daNote.mustPress ? playerStrums.members[daNote.noteData] : cpuStrums.members[daNote.noteData];
#if FEATURE_HSCRIPT
if (!ScriptUtil.hasPause(scripts.executeAllFunc("notesUpdate", [daNote])))
@@ -2379,9 +2297,6 @@ class PlayState extends MusicBeatState
handleHolds(daNote);
}
- if (!daNote.mustPress && PlayStateChangeables.middleScroll && !executeModchart)
- daNote.visible = false;
-
if (daNote.exists)
{
if (Conductor.elapsedPosition > Ratings.timingWindows[0].timingWindow + daNote.strumTime)
@@ -2433,9 +2348,6 @@ class PlayState extends MusicBeatState
if (!daNote.wasGoodHit && daNote.isSustainNote && daNote.sustainActive && !daNote.isSustainEnd && daNote.causesMisses
&& !keys[daNote.noteData])
{
- // there should be a ! infront of the wasGoodHit one but it'd cause a miss per every sustain note.
- // now it just misses on the slightest sustain end for some reason.
- // nvm I fixed it a long time ago
Debug.logTrace("User released key while playing a sustain at: " + daNote.spotInLine);
for (i in daNote.parent.children)
{
@@ -2566,6 +2478,7 @@ class PlayState extends MusicBeatState
}
storyPlaylist.shift();
+ Conductor.songPosition = inst.length - 1;
#if FEATURE_HSCRIPT
if (ScriptUtil.hasPause(scripts.executeAllFunc("endSong")))
@@ -2899,7 +2812,7 @@ class PlayState extends MusicBeatState
{
if (daNote.causesMisses)
{
- if (gf != null && combo > 5 && gf.offsets.exists('sad') && !PlayStateChangeables.opponentMode)
+ if (gf != null && combo > 5 && gf.offsets.exists('sad'))
gf.playAnim('sad');
if (combo != 0)
combo = 0;
@@ -2921,8 +2834,6 @@ class PlayState extends MusicBeatState
}
var char:Character = boyfriend;
- if (PlayStateChangeables.opponentMode)
- char = dad;
if (char.offsets.exists(Constants.singAnimations[direction] + 'miss'))
char.playAnim(Constants.singAnimations[direction] + 'miss', true);
@@ -3040,8 +2951,6 @@ class PlayState extends MusicBeatState
if (daNote.canPlayAnims)
{
var char:Character = dad;
- if (PlayStateChangeables.opponentMode)
- char = boyfriend;
if (daNote.noteType.toLowerCase() == 'gf' && gf != null)
char = gf;
@@ -3074,7 +2983,7 @@ class PlayState extends MusicBeatState
{
if (FlxG.save.data.cpuStrums)
{
- if (FlxG.save.data.cpuSplash && daNote.canNoteSplash && !PlayStateChangeables.middleScroll)
+ if (FlxG.save.data.cpuSplash && daNote.canNoteSplash)
{
spawnNoteSplashOnNote(daNote);
}
@@ -3083,10 +2992,7 @@ class PlayState extends MusicBeatState
#if FEATURE_LUAMODCHART
if (luaModchart != null)
- if (!PlayStateChangeables.opponentMode)
- luaModchart.executeState('playerTwoSing', [Math.abs(daNote.noteData), Conductor.elapsedPosition]);
- else
- luaModchart.executeState('playerOneSing', [Math.abs(daNote.noteData), Conductor.elapsedPosition]);
+ luaModchart.executeState('opponentNoteHit', [Math.abs(daNote.noteData), Conductor.elapsedPosition]);
#end
#if FEATURE_HSCRIPT
@@ -3102,8 +3008,6 @@ class PlayState extends MusicBeatState
function goodNoteHit(note:Note):Void
{
- if (PlayStateChangeables.opponentMode)
- camZooming = FlxG.save.data.camzoom;
// add newest note to front of notesHitArray
// the oldest notes are at the end and are removed first
@@ -3145,8 +3049,6 @@ class PlayState extends MusicBeatState
if (!note.isSustainEnd)
{
var char:Character = boyfriend;
- if (PlayStateChangeables.opponentMode)
- char = dad;
switch (note.noteType.toLowerCase())
{
@@ -3183,10 +3085,7 @@ class PlayState extends MusicBeatState
#if FEATURE_LUAMODCHART
if (luaModchart != null)
- if (!PlayStateChangeables.opponentMode)
- luaModchart.executeState('playerOneSing', [Math.abs(note.noteData), Conductor.elapsedPosition]);
- else
- luaModchart.executeState('playerTwoSing', [Math.abs(note.noteData), Conductor.elapsedPosition]);
+ luaModchart.executeState('goodNoteHit', [Math.abs(note.noteData), Conductor.elapsedPosition]);
#end
#if FEATURE_HSCRIPT
@@ -3230,9 +3129,7 @@ class PlayState extends MusicBeatState
if (spr != null)
{
if (!FlxG.save.data.stepMania)
- {
spr.playAnim('confirm', true);
- }
else
{
spr.localAngle = daNote.originAngle;
@@ -4138,7 +4035,6 @@ class PlayState extends MusicBeatState
// Initialize PlayStateChangeables Options For Later.
PlayStateChangeables.useDownscroll = FlxG.save.data.downscroll;
PlayStateChangeables.middleScroll = FlxG.save.data.middleScroll;
- PlayStateChangeables.safeFrames = FlxG.save.data.frames;
if (FlxG.save.data.scrollSpeed == 1)
scrollSpeed = SONG.speed;
else
@@ -4147,30 +4043,15 @@ class PlayState extends MusicBeatState
PlayStateChangeables.botPlay = FlxG.save.data.botplay;
PlayStateChangeables.noteCamera = FlxG.save.data.noteCamera;
- if (!isStoryMode)
- {
- PlayStateChangeables.modchart = FlxG.save.data.modcharts;
- PlayStateChangeables.opponentMode = FlxG.save.data.opponent;
- PlayStateChangeables.mirrorMode = FlxG.save.data.mirror;
- PlayStateChangeables.holds = FlxG.save.data.sustains;
- PlayStateChangeables.healthDrain = FlxG.save.data.hdrain;
- PlayStateChangeables.healthGain = FlxG.save.data.hgain;
- PlayStateChangeables.healthLoss = FlxG.save.data.hloss;
- PlayStateChangeables.practiceMode = FlxG.save.data.practice;
- PlayStateChangeables.skillIssue = FlxG.save.data.noMisses;
- }
- else
- {
- PlayStateChangeables.modchart = true;
- PlayStateChangeables.opponentMode = false;
- PlayStateChangeables.mirrorMode = false;
- PlayStateChangeables.holds = true;
- PlayStateChangeables.healthDrain = false;
- PlayStateChangeables.healthGain = 1;
- PlayStateChangeables.healthLoss = 1;
- PlayStateChangeables.practiceMode = false;
- PlayStateChangeables.skillIssue = false;
- }
+ PlayStateChangeables.modchart = !isStoryMode ? FlxG.save.data.modcharts : true;
+ // PlayStateChangeables.opponentMode = !isStoryMode ? FlxG.save.data.opponent : false;
+ PlayStateChangeables.mirrorMode = !isStoryMode ? FlxG.save.data.mirror : false;
+ PlayStateChangeables.holds = !isStoryMode ? FlxG.save.data.sustains : true;
+ PlayStateChangeables.healthDrain = !isStoryMode ? FlxG.save.data.hdrain : false;
+ PlayStateChangeables.healthGain = !isStoryMode ? FlxG.save.data.hgain : 1.0;
+ PlayStateChangeables.healthLoss = !isStoryMode ? FlxG.save.data.hloss : 1.0;
+ PlayStateChangeables.practiceMode = !isStoryMode ? FlxG.save.data.practice : false;
+ PlayStateChangeables.skillIssue = !isStoryMode ? FlxG.save.data.noMisses : false;
}
private function initStyle()
@@ -4381,6 +4262,31 @@ class PlayState extends MusicBeatState
}
}
+ private function setConductorTime()
+ {
+ if (!startedCountdown && endingSong)
+ return;
+
+ // we don't need to update after the song ended
+
+ Conductor.elapsedPosition += FlxG.elapsed * 1000;
+
+ if (Conductor.elapsedPosition > 0 && startingSong)
+ startSong();
+
+ if (songStarted && !endingSong && (inst.length / Conductor.rate) - Conductor.elapsedPosition <= 0)
+ endSong();
+ Conductor.songPosition = Conductor.elapsedPosition * Conductor.rate;
+ final curTime:Float = Math.max(0, Conductor.songPosition) / Conductor.rate;
+ songPositionBar = CoolUtil.fpsLerp(songPositionBar, (curTime / songLength), 0.15, 60 * Conductor.rate);
+ final songCalc:Float = (songLength - curTime);
+ var secondsTotal:Int = Math.floor(songCalc * 0.001);
+ if (secondsTotal < 0)
+ secondsTotal = 0;
+ songName.text = SONG.songName + ' (' + FlxStringUtil.formatTime(secondsTotal, false) + ')';
+ checkMusicSync();
+ }
+
private function set_health(v:Float)
{
if (v <= 0)
diff --git a/source/kec/states/SelectEditorsState.hx b/source/kec/states/SelectEditorsState.hx
index 294f7cd0..a825613b 100644
--- a/source/kec/states/SelectEditorsState.hx
+++ b/source/kec/states/SelectEditorsState.hx
@@ -148,7 +148,6 @@ class SelectEditorsState extends MusicBeatState
PlayState.storyDifficulty = 1;
PlayState.storyWeek = 0;
PlayState.isStoryMode = false;
- PlayState.isSM = false;
Conductor.rate = 1;
MusicBeatState.switchState(new kec.states.editors.ChartingState());
}
diff --git a/source/kec/states/StoryMenuState.hx b/source/kec/states/StoryMenuState.hx
index 42ec51f9..283e19d6 100644
--- a/source/kec/states/StoryMenuState.hx
+++ b/source/kec/states/StoryMenuState.hx
@@ -222,17 +222,6 @@ class StoryMenuState extends MusicBeatState
bullShit++;
}
- PlayStateChangeables.modchart = true;
- PlayStateChangeables.opponentMode = false;
- PlayStateChangeables.mirrorMode = false;
- PlayStateChangeables.holds = true;
- PlayStateChangeables.healthDrain = false;
- PlayStateChangeables.healthGain = 1;
- PlayStateChangeables.healthLoss = 1;
- PlayStateChangeables.practiceMode = false;
- PlayStateChangeables.skillIssue = false;
-
- trace("Line 165");
changeWeek();
changeDifficulty();
@@ -350,7 +339,6 @@ class StoryMenuState extends MusicBeatState
PlayState.storyPlaylist = weeksLoaded[curWeek].songs;
PlayState.isStoryMode = true;
Conductor.rate = 1;
- PlayState.isSM = false;
PlayState.storyWeek = curWeek;
PlayState.storyDifficulty = CoolUtil.difficulties.indexOf(diffString);
diff --git a/source/kec/states/editors/CharacterEditorState.hx b/source/kec/states/editors/CharacterEditorState.hx
index 382f0595..84a8f2e1 100644
--- a/source/kec/states/editors/CharacterEditorState.hx
+++ b/source/kec/states/editors/CharacterEditorState.hx
@@ -637,6 +637,7 @@ class CharacterEditorState extends UIState
curAnim.prefix = animPrefix.text;
curAnim.frameIndices = newIndices;
curAnim.looped = animLooped.selected;
+ curAnim.interrupt = animIgnoreIdle.selected;
char.playAnim(char.data.animations[0].name, true);
char.animation.remove(curAnim.name);
addAnimation(curAnim.name, curAnim.prefix, curAnim.frameRate, curAnim.looped, newIndices);
diff --git a/source/kec/states/editors/ChartingState.hx b/source/kec/states/editors/ChartingState.hx
index 93dd4afb..2ccc2b37 100644
--- a/source/kec/states/editors/ChartingState.hx
+++ b/source/kec/states/editors/ChartingState.hx
@@ -6,7 +6,7 @@ import kec.objects.editor.EditorSustain;
import kec.backend.HitSounds;
import kec.backend.PlayStateChangeables;
import kec.backend.chart.Event;
-import kec.backend.chart.format.Modern;
+import kec.backend.chart.ChartData;
import kec.backend.chart.Song;
import kec.backend.chart.TimingStruct;
import kec.backend.util.HelperFunctions;
@@ -20,15 +20,16 @@ import kec.objects.editor.ChartingBox;
import openfl.Lib;
import openfl.events.Event as OpenFlEvent;
import openfl.events.IOErrorEvent;
-import openfl.net.FileReference;
import kec.backend.chart.ChartNote;
-import kec.backend.chart.format.Section;
+import kec.backend.chart.Section;
import kec.objects.editor.EditorNote;
import kec.objects.editor.EditorGrid;
import kec.objects.editor.BeatLine;
import haxe.ui.data.ArrayDataSource;
import haxe.ui.focus.FocusManager;
import flixel.util.FlxSort;
+import kec.backend.util.FileDialogHandler;
+import haxe.ui.events.UIEvent;
#if FEATURE_FILESYSTEM
import sys.FileSystem;
import sys.io.File;
@@ -39,7 +40,7 @@ class ChartingState extends UIState
{
public static var instance:ChartingState = null;
- public var SONG:Modern;
+ public var SONG:ChartData;
public var lastUpdatedSection:Section = null;
@@ -75,8 +76,12 @@ class ChartingState extends UIState
public var selectBox:FlxSprite;
- private var savedEvent:Event = null;
private var curSelectedNote:ChartNote;
+ private var curEvent:Event;
+
+ var eventList:Array = []; // existing events
+ var eventIndex:Int = 0;
+ var existingEvents = new ArrayDataSource(); // bullshit
private var noteGroup:FlxTypedSpriteGroup;
private var sustainGroup:FlxTypedSpriteGroup;
@@ -117,12 +122,15 @@ class ChartingState extends UIState
private var noteTypes:Array = null;
- private var _file:FileReference;
-
public var id:Int = -1;
private var noteCounter:Int = 0;
+ private var maxNotes:Int = 0;
+ private var unspawnNotes:Array = [];
+
+ var fileDialog:FileDialogHandler = new FileDialogHandler();
+
// one does not realize how much flixel-ui is used until one sees an FNF chart editor. 💀
/*
@@ -174,7 +182,17 @@ class ChartingState extends UIState
checkforSections();
setInitVars();
+ for (sec in SONG.notes)
+ for (i in sec.sectionNotes)
+ {
+ unspawnNotes.push(i);
+ maxNotes++;
+ }
+
+ Debug.logTrace(maxNotes);
+
activeSong = SONG;
+ curEvent = SONG.eventObjects[0];
Debug.logTrace('${TimingStruct.AllTimings.length} ${curTiming.endBeat}');
lengthInBeats = Math.round(TimingStruct.getBeatFromTime(inst.length));
lengthInSteps = lengthInBeats * 4;
@@ -339,8 +357,8 @@ class ChartingState extends UIState
// final lerpVal:Float = CoolUtil.boundTo(1 - (elapsed * 12), 0, 1);
// strumLine.y = FlxMath.lerp(getYFromTime(inst.time), strumLine.y, lerpVal);
strumLine.y = getYFromTime(Conductor.songPosition);
- var mouseX:Float = quantizePos(FlxG.mouse.x - grid.x);
- mouse.x = Math.min(grid.x + mouseX + separatorWidth * Math.floor(mouseX / gridSize / 4), grid.x + grid.width);
+ var diffX:Float = FlxG.mouse.x - grid.x;
+ mouse.x = grid.x + Math.floor(diffX / gridSize) * gridSize;
mouse.y = FlxMath.bound(getMouseY(), 0, end - gridSize);
mouse.visible = mouseValid();
@@ -534,22 +552,36 @@ class ChartingState extends UIState
scroll(FlxG.mouse.wheel);
}
- while (noteCounter < currentSection.sectionNotes.length)
+ if (unspawnNotes.length > 0)
{
- final chartNote = currentSection.sectionNotes[noteCounter];
- var note:EditorNote = noteGroup.recycle(EditorNote);
- note.setup(chartNote.time, chartNote.data, chartNote.length, chartNote.type, TimingStruct.getBeatFromTime(chartNote.time));
- note.setGraphicSize(gridSize, gridSize);
- note.updateHitbox();
- note.setPosition(grid.x + (gridSize * chartNote.data), getYFromTime(chartNote.time));
- if (note.holdLength > 0)
+ while (unspawnNotes[noteCounter] != null && unspawnNotes[noteCounter].time - Conductor.songPosition < 1800)
{
- var sustain:EditorSustain = sustainGroup.recycle(EditorSustain);
- sustain.setup(note.x + 20, note.y + gridSize, 8, Math.floor((getYFromTime(note.time + note.holdLength)) - note.y));
- note.sustain = sustain;
+ var spawnNote = unspawnNotes[noteCounter];
+ var note:EditorNote = noteGroup.recycle(EditorNote);
+ note.setup(spawnNote.time, spawnNote.data, spawnNote.length, spawnNote.type, TimingStruct.getBeatFromTime(spawnNote.time));
+ note.setGraphicSize(gridSize, gridSize);
+ note.updateHitbox();
+ note.setPosition(grid.x + (gridSize * spawnNote.data), getYFromTime(spawnNote.time));
+ noteCounter++;
+ if (note.holdLength > 0)
+ {
+ var sustain:EditorSustain = sustainGroup.recycle(EditorSustain);
+ sustain.setup(note.x + 20, note.y + gridSize, 8, Math.floor((getYFromTime(note.time + note.holdLength)) - note.y));
+ note.sustain = sustain;
+ }
+ // noteGroup.sort(FlxSort.byY, FlxSort.ASCENDING);
+ // sustainGroup.sort(FlxSort.byY, -1);
}
- noteCounter++;
- noteGroup.sort(FlxSort.byY, FlxSort.ASCENDING);
+
+ noteGroup.forEachAlive(function(n:EditorNote)
+ {
+ if (Conductor.songPosition - n.time > 1000)
+ {
+ n.kill();
+ if (n.sustain != null)
+ n.sustain.kill();
+ }
+ });
}
var playedSound:Array = [false, false, false, false, false, false, false, false];
@@ -560,8 +592,8 @@ class ChartingState extends UIState
if (note.time > lastConductorPos && inst.playing && note.data > -1 && note.hitsoundsEditor)
{
var data:Int = note.rawData;
- var noteDataToCheck:Int = data;
- var playerNote = noteDataToCheck >= 4;
+ final noteDataToCheck:Int = data;
+ final playerNote = noteDataToCheck >= 4;
if (!playedSound[data])
{
if ((FlxG.save.data.playHitsounds && playerNote) || (FlxG.save.data.playHitsoundsE && !playerNote))
@@ -622,30 +654,32 @@ class ChartingState extends UIState
}
for (i in SONG.eventObjects)
- {
- final seg = TimingStruct.getTimingAtBeat(i.beat);
- var posi:Float = 0;
- if (seg != null)
- {
- var start:Float = (i.beat - seg.startBeat) / (seg.bpm / 60);
- posi = seg.startTime + start;
- }
+ addEventLine(i);
+ }
- var pos = getYFromTime(posi * 1000);
+ private function addEventLine(i:Event)
+ {
+ final seg = TimingStruct.getTimingAtBeat(i.beat);
+ var posi:Float = 0;
+ if (seg != null)
+ {
+ var start:Float = (i.beat - seg.startBeat) / (seg.bpm / 60);
+ posi = seg.startTime + start;
+ }
- if (pos < 0)
- pos = 0;
+ var pos = getYFromTime(posi * 1000);
+ if (pos < 0)
+ pos = 0;
- var type = i.type;
+ final type = i.type;
- final text:TextLine = texts.recycle(TextLine);
- text.reuse(grid.x + (gridSize * 8) + separatorWidth, pos, 16);
- text.text = i.name + "\n" + type + "\n" + i.args[0] + "\n" + i.args[1];
- text.updateHitbox();
+ final text:TextLine = texts.recycle(TextLine);
+ text.reuse(grid.x + (gridSize * 8), pos, 16);
+ text.text = i.name + "\n" + type + "\n" + i.args[0] + "\n" + (i.args[1] == null ? "" : i.args[1]);
+ text.updateHitbox();
- final line:BeatLine = lines.recycle(BeatLine);
- line.setup(grid.x, pos, FlxColor.YELLOW);
- }
+ final line:BeatLine = lines.recycle(BeatLine);
+ line.setup(grid.x, pos, FlxColor.YELLOW);
}
private function addNote()
@@ -667,6 +701,7 @@ class ChartingState extends UIState
note.setPosition(grid.x + (gridSize * chartNote.data), getYFromTime(chartNote.time));
note.camera = noteGroup.camera;
noteCounter++;
+ maxNotes++;
section.sectionNotes.push(chartNote);
sortNotes(section);
noteGroup.sort(FlxSort.byY, FlxSort.ASCENDING);
@@ -915,31 +950,30 @@ class ChartingState extends UIState
final audioFile:String = SONG.audioFile;
- inst = new FlxSound().loadEmbedded(Paths.inst(audioFile));
+ inst = FlxG.sound.load(Paths.inst(audioFile, false));
inst.play();
inst.pause();
- FlxG.sound.list.add(inst);
vocals = new FlxSound();
vocalsP = new FlxSound();
vocalsE = new FlxSound();
+ if (!SONG.needsVoices)
+ return;
+ // I love doing this but it's so situational bruh
switch (SONG.splitVoiceTracks)
{
case true:
- vocalsP.loadEmbedded(Paths.voices(audioFile, 'P'));
- vocalsE.loadEmbedded(Paths.voices(audioFile, 'E'));
+ vocalsP = FlxG.sound.load(Paths.voices(audioFile, 'P'));
+ vocalsE = FlxG.sound.load(Paths.voices(audioFile, 'E'));
vocalsP.play();
vocalsP.pause();
vocalsE.play();
vocalsE.pause();
case false:
- vocals.loadEmbedded(Paths.voices(audioFile));
+ vocals = FlxG.sound.load(Paths.voices(audioFile, ''));
vocals.play();
vocals.pause();
}
- FlxG.sound.list.add(vocals);
- FlxG.sound.list.add(vocalsP);
- FlxG.sound.list.add(vocalsE);
}
function loadJson(songId:String, diff:String):Void
@@ -962,48 +996,10 @@ class ChartingState extends UIState
private function saveChart()
{
SONG.chartVersion = Constants.chartVer;
-
+ setSongData();
final data:String = haxe.Json.stringify(SONG, null).trim();
-
- if ((data != null) && (data.length > 0))
- {
- _file = new FileReference();
- _file.addEventListener(#if desktop OpenFlEvent.SELECT #else OpenFlEvent.COMPLETE #end, onSaveComplete);
- _file.addEventListener(OpenFlEvent.CANCEL, onSaveCancel);
- _file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
- _file.save(data.trim(), SONG.songId.toLowerCase() + CoolUtil.getSuffixFromDiff(curDiff) + ".json");
- }
- }
-
- function onSaveComplete(_):Void
- {
- _file.removeEventListener(OpenFlEvent.COMPLETE, onSaveComplete);
- _file.removeEventListener(OpenFlEvent.CANCEL, onSaveCancel);
- _file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
- _file = null;
- }
-
- /**
- * Called when the save file dialog is cancelled.
- */
- function onSaveCancel(_):Void
- {
- _file.removeEventListener(OpenFlEvent.COMPLETE, onSaveComplete);
- _file.removeEventListener(OpenFlEvent.CANCEL, onSaveCancel);
- _file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
- _file = null;
- }
-
- /**
- * Called if there is an error while saving the gameplay recording.
- */
- function onSaveError(_):Void
- {
- _file.removeEventListener(OpenFlEvent.COMPLETE, onSaveComplete);
- _file.removeEventListener(OpenFlEvent.CANCEL, onSaveCancel);
- _file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
- _file = null;
- FlxG.log.error("Problem saving Level data");
+ final chartName:String = SONG.songId + CoolUtil.getSuffixFromDiff(curDiff);
+ fileDialog.save('$chartName.json', data, function() Debug.logTrace("Successfully Saved Chart"), null, function() Debug.logTrace("Error Saving Chart"));
}
private function setSongData()
@@ -1028,7 +1024,7 @@ class ChartingState extends UIState
if (curSection < 0)
return;
- clearRenderedNotes();
+ // clearRenderedNotes();
sectionMustHit.selected = currentSection.mustHitSection;
}
@@ -1051,7 +1047,7 @@ class ChartingState extends UIState
inline function mouseValid():Bool
{
// NOTE: we're checking the mouse's y so notes/events can't be placed outside of the grid
- return mouse.x >= grid.x - separatorWidth && mouse.x < grid.x + grid.width && FlxG.mouse.y >= 0 && FlxG.mouse.y < end;
+ return mouse.x >= grid.x && mouse.x < grid.x + grid.width && FlxG.mouse.y >= 0 && FlxG.mouse.y < end;
}
inline function getMouseY():Float
@@ -1074,12 +1070,11 @@ class ChartingState extends UIState
private function checkNoteSpawn()
{
- final strumTime = getTimeFromY(mouse.y);
+ final strumTime:Float = getTimeFromY(mouse.y);
final noteData:Int = Math.floor((mouse.x - grid.x) / gridSize);
- var existingNote = noteGroup.members.filter(function(n:EditorNote)
+ final existingNote = noteGroup.members.filter(function(n:EditorNote)
{
- final real = (n.time == strumTime && n.rawData == noteData && n.alive);
- return real;
+ return (n.time == strumTime && n.rawData == noteData && n.alive && FlxG.mouse.overlaps(n));
});
if (existingNote[0] != null)
@@ -1253,7 +1248,6 @@ class ChartingState extends UIState
{
noteGroup.forEachAlive(function(n:EditorNote) n.kill());
sustainGroup.forEachAlive(function(n:EditorSustain) n.kill());
- noteCounter = 0;
}
private function playMetronome()
@@ -1275,6 +1269,19 @@ class ChartingState extends UIState
return sec;
}
+ private function findEvent(name:String, type:String)
+ {
+ var theEVENT = eventList.filter(function(e:Event)
+ {
+ final ev = (e.name == name && e.type == type);
+ return ev;
+ });
+
+ Debug.logTrace(theEVENT[0] == null);
+
+ return theEVENT[0] == null ? null : theEVENT[0];
+ }
+
public inline function sortNotes(sec:Section):Void
sec.sectionNotes.sort((a, b) -> Std.int(a.time - b.time));
@@ -1284,6 +1291,7 @@ class ChartingState extends UIState
final gfList:Array = CoolUtil.coolTextFile(Paths.txt('data/gfVersionList'));
final stageList:Array = CoolUtil.coolTextFile(Paths.txt('data/stageList'));
final styleList:Array = CoolUtil.coolTextFile(Paths.txt('data/songStyleList'));
+ final eventList:Array = CoolUtil.coolTextFile(Paths.txt('data/eventList'));
final diffList:Array = CoolUtil.difficulties;
var chars = new ArrayDataSource();
for (c in characterList)
@@ -1304,12 +1312,40 @@ class ChartingState extends UIState
for (d in diffList)
diffs.add(d);
+ var events = new ArrayDataSource();
+ for (e in eventList)
+ events.add(e);
+ for (event in SONG.eventObjects)
+ {
+ existingEvents.add(event.name);
+ this.eventList.push(event);
+ }
+
playerSelect.dataSource = chars;
opponentSelect.dataSource = chars;
gfSelect.dataSource = gfs;
stageSelect.dataSource = stages;
styleSelect.dataSource = styles;
diffSelect.dataSource = diffs;
+ eventExistList.dataSource = existingEvents;
+ eventTypes.dataSource = events;
+
+ eventTypes.selectItemBy(item -> item == SONG.eventObjects[0].type, true);
+ eventExistList.selectItemBy(item -> item == SONG.eventObjects[0].name, true);
+ eventExistList.registerEvent(UIEvent.CLOSE, function(e:UIEvent)
+ {
+ curEvent = SONG.eventObjects[eventExistList.selectedIndex];
+ Debug.logTrace(curEvent.name);
+ if (findEvent(curEvent.name, curEvent.type) == null)
+ return;
+
+ eventName.value = curEvent.name;
+ eventTypes.selectItemBy(item -> item == curEvent.type, true);
+ eventValue1.value = curEvent.args[0];
+ eventValue2.value = curEvent.args[1];
+ eventPos.pos = curEvent.beat;
+ Debug.logTrace("Found Event. Setting Values");
+ });
setHUIData();
}
@@ -1322,11 +1358,17 @@ class ChartingState extends UIState
stageSelect.selectItemBy(item -> item == SONG.stage, true);
styleSelect.selectItemBy(item -> item == SONG.style, true);
diffSelect.selectItemBy(item -> item == CoolUtil.difficulties[PlayState.storyDifficulty], true);
+ eventName.text = curEvent.name;
+ eventValue1.text = curEvent.args[0];
+ eventValue2.text = curEvent.args[1];
+ eventPos.pos = curEvent.beat;
dataID.text = SONG.songId;
dataName.text = SONG.songName;
dataAudio.text = SONG.audioFile;
dataBPM.pos = SONG.eventObjects[0].args[0];
+ dataVoices.selected = SONG.needsVoices;
dataSpeed.pos = SONG.speed;
+ dataSplit.selected = SONG.splitVoiceTracks;
sectionMustHit.onClick = _ -> currentSection.mustHitSection = !currentSection.mustHitSection;
editorMetroVol.onChange = _ -> metronome.volume = (editorMetroVol.value / 100);
@@ -1342,12 +1384,12 @@ class ChartingState extends UIState
chartSave.onClick = _ -> saveChart();
chartReload.onClick = _ -> loadAudio(dataID.text, true);
- diffSelect.registerEvent(haxe.ui.events.UIEvent.CLOSE, function(e)
+ diffSelect.registerEvent(UIEvent.CLOSE, function(e)
{
PlayState.storyDifficulty = CoolUtil.difficulties.indexOf(diffSelect.text);
Debug.logTrace(CoolUtil.difficulties[PlayState.storyDifficulty]);
});
- chartClear.onClick = function(e)
+ chartClear.onClick = function(e)
{
for (i in 0...maxSectionIndex)
{
@@ -1363,5 +1405,37 @@ class ChartingState extends UIState
vocalVol.onChange = _ -> if (vocals != null && !vocalVol.disabled) vocals.volume = (vocalVol.value / 100);
vocalPVol.onChange = _ -> if (vocalsP != null && !vocalPVol.disabled) vocalsP.volume = (vocalPVol.value / 100);
vocalEVol.onChange = _ -> if (vocalsE != null && !vocalEVol.disabled) vocalsE.volume = (vocalEVol.value / 100);
+ dataSplit.onClick = function(e)
+ {
+ SONG.splitVoiceTracks = !SONG.splitVoiceTracks;
+ loadAudio(SONG.songId);
+ }
+ dataVoices.onClick = function(e)
+ {
+ SONG.needsVoices = !SONG.needsVoices;
+ loadAudio(SONG.songId);
+ }
+ eventAdd.onClick = function(e)
+ {
+ final eventPos = TimingStruct.getBeatFromTime(Conductor.songPosition);
+ if (findEvent('New Event $eventPos', "BPM Change") != null)
+ {
+ Debug.logTrace("Event Already Exists Dumbass");
+ return;
+ }
+ final newEvent:Event = {
+ name: 'New Event $eventPos',
+ type: "BPM Change",
+ args: [SONG.eventObjects[0].args[0]],
+ beat: eventPos
+ };
+
+ SONG.eventObjects.push(newEvent);
+ eventList.push(newEvent);
+ existingEvents.add(newEvent.name);
+ eventExistList.dataSource = existingEvents;
+ eventExistList.selectItemBy(item -> item == newEvent.name, true);
+ addEventLine(newEvent);
+ }
}
}
diff --git a/source/kec/states/editors/StageDebugState.hx b/source/kec/states/editors/StageDebugState.hx
index 76f09e7b..038fbd50 100644
--- a/source/kec/states/editors/StageDebugState.hx
+++ b/source/kec/states/editors/StageDebugState.hx
@@ -385,7 +385,6 @@ class StageDebugState extends UIState
Stage.inEditor = true;
Stage.loadStageData(leStage);
Stage.initStageProperties();
-
Stage.initCamPos();
diff --git a/source/kec/substates/GameOverSubstate.hx b/source/kec/substates/GameOverSubstate.hx
index ce117894..cf4b3043 100644
--- a/source/kec/substates/GameOverSubstate.hx
+++ b/source/kec/substates/GameOverSubstate.hx
@@ -24,9 +24,6 @@ class GameOverSubstate extends MusicBeatSubstate
var daBf:String = '';
var char:Character = PlayState.instance.boyfriend;
- if (PlayStateChangeables.opponentMode)
- char = PlayState.instance.dad;
-
var styleShit:String = (PlayState.STYLE.style == null ? 'default' : PlayState.STYLE.style).toLowerCase();
var daBf:String = '';
switch (char.data.char)
@@ -88,7 +85,7 @@ class GameOverSubstate extends MusicBeatSubstate
FlxG.camera.follow(camFollow, LOCKON, 0.01);
}
- if (!PlayStateChangeables.opponentMode && bf.animation.curAnim.name == 'firstDeath' && bf.animation.curAnim.finished)
+ if (bf.animation.curAnim.name == 'firstDeath' && bf.animation.curAnim.finished)
{
if (PlayState.SONG.stage == 'tank')
{
diff --git a/source/kec/substates/ResultsScreen.hx b/source/kec/substates/ResultsScreen.hx
index 3802cd17..853d4d76 100644
--- a/source/kec/substates/ResultsScreen.hx
+++ b/source/kec/substates/ResultsScreen.hx
@@ -58,7 +58,7 @@ class ResultsScreen extends MusicBeatSubstate
if (!PlayState.isStoryMode)
{
- modifiers = 'Active Modifiers:\n${(PlayStateChangeables.opponentMode ? '- Opponent Mode\n' : '')}${(PlayStateChangeables.mirrorMode ? '- Mirror Mode\n' : '')}${(PlayStateChangeables.practiceMode ? '- Practice Mode\n' : '')}${(PlayStateChangeables.skillIssue ? '- No Misses mode\n' : '')}${(!PlayStateChangeables.holds ? '- Hold Notes OFF\n' : '')}${(!PlayStateChangeables.modchart #if FEATURE_LUAMODCHART && FileSystem.exists(Paths.lua('songs/${PlayState.SONG.songId}/modchart')) #end ? '- Song modchart OFF\n' : '')}${(PlayStateChangeables.healthDrain ? '- Health Drain ON\n' : '')}${(HelperFunctions.truncateFloat(PlayStateChangeables.healthGain,2) != 1 ? '- HP Gain ${HelperFunctions.truncateFloat(PlayStateChangeables.healthGain, 2)}x\n': '')}${(HelperFunctions.truncateFloat(PlayStateChangeables.healthLoss,2) != 1 ? '- HP Loss ${HelperFunctions.truncateFloat(PlayStateChangeables.healthLoss, 2)}x\n':'')}';
+ modifiers = 'Active Modifiers:\n${(PlayStateChangeables.mirrorMode ? '- Mirror Mode\n' : '')}${(PlayStateChangeables.practiceMode ? '- Practice Mode\n' : '')}${(PlayStateChangeables.skillIssue ? '- No Misses mode\n' : '')}${(!PlayStateChangeables.holds ? '- Hold Notes OFF\n' : '')}${(!PlayStateChangeables.modchart #if FEATURE_LUAMODCHART && FileSystem.exists(Paths.lua('songs/${PlayState.SONG.songId}/modchart')) #end ? '- Song modchart OFF\n' : '')}${(PlayStateChangeables.healthDrain ? '- Health Drain ON\n' : '')}${(HelperFunctions.truncateFloat(PlayStateChangeables.healthGain,2) != 1 ? '- HP Gain ${HelperFunctions.truncateFloat(PlayStateChangeables.healthGain, 2)}x\n': '')}${(HelperFunctions.truncateFloat(PlayStateChangeables.healthLoss,2) != 1 ? '- HP Loss ${HelperFunctions.truncateFloat(PlayStateChangeables.healthLoss, 2)}x\n':'')}';
if (modifiers == 'Active Modifiers:\n')
modifiers = 'Active Modifiers: None';
activeMods = new FlxText(FlxG.width - 500, FlxG.height - 450, FlxG.width, modifiers);