diff --git a/README.md b/README.md
index ac87a79c..604cd9c2 100644
--- a/README.md
+++ b/README.md
@@ -30,22 +30,10 @@ In the future (when the engine won't be a WIP anymore) we're gonna also publish
##### Tested on Windows 10 21H2
1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/).
-2. Download [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe)
-3. Wait for the Visual Studio Installer to install
-4. On the Visual Studio installer screen, go to the "Individual components" tab and only select those options:
- - MSVC v143 VS 2022 C++ x64/x86 build tools (Latest)
- - Windows 10/11 SDK (any works)
-5. This is what your Installation details panel should look like. Once correct, press "Install".
- - ⚠ This will download around 1.07 GB of data from the internet, and will require around 5.5 GB of available space on your computer.
-
-
-
-
-
-6. Once you finish downloading those components, download and install [`git-scm`](https://git-scm.com/download/win).
+2. Download and install [`git-scm`](https://git-scm.com/download/win).
- Leave all installation options as default.
-7. Run `update.bat` using cmd or double-clicking it, and wait for the libraries to install.
-8. Once the libraries are installed, run `haxelib run lime test windows` to compile and launch the game (may take a long time)
+3. Run `update.bat` using cmd or double-clicking it, and wait for the libraries to install.
+4. Once the libraries are installed, run `haxelib run lime test windows` to compile and launch the game (may take a long time)
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test windows` directly.
diff --git a/assets/data/characters/gf.xml b/assets/data/characters/gf.xml
index 44c6f9e5..e9ac6776 100644
--- a/assets/data/characters/gf.xml
+++ b/assets/data/characters/gf.xml
@@ -7,7 +7,7 @@
-
+
diff --git a/assets/data/stages/philly.hx b/assets/data/stages/philly.hx
index 2a4b9780..989b29b5 100644
--- a/assets/data/stages/philly.hx
+++ b/assets/data/stages/philly.hx
@@ -90,7 +90,7 @@ function updateTrainPos():Void
function trainReset():Void
{
- gf.playAnim('hairFall');
+ gf.playAnim('hairFall', true);
phillyTrain.x = FlxG.width + 200;
trainMoving = false;
// trainSound.stop();
diff --git a/assets/data/stages/school.xml b/assets/data/stages/school.xml
index e4c4d5e1..dabf463b 100644
--- a/assets/data/stages/school.xml
+++ b/assets/data/stages/school.xml
@@ -23,7 +23,7 @@
antialiasing="false" scale="6" scroll="0.85" updateHitbox="true" type="loop"/>
-
+
diff --git a/assets/data/titlescreen/titlescreen.xml b/assets/data/titlescreen/titlescreen.xml
index 0ff1053b..f16c8b62 100644
--- a/assets/data/titlescreen/titlescreen.xml
+++ b/assets/data/titlescreen/titlescreen.xml
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/assets/images/editors/deleter circle.png b/assets/images/editors/deleter circle.png
new file mode 100644
index 00000000..7d63d069
Binary files /dev/null and b/assets/images/editors/deleter circle.png differ
diff --git a/assets/images/editors/deleter.png b/assets/images/editors/deleter.png
new file mode 100644
index 00000000..8146955d
Binary files /dev/null and b/assets/images/editors/deleter.png differ
diff --git a/assets/images/editors/ui/context-icons.png b/assets/images/editors/ui/context-icons.png
index 91976656..a9de6358 100644
Binary files a/assets/images/editors/ui/context-icons.png and b/assets/images/editors/ui/context-icons.png differ
diff --git a/assets/shaders/engine/circleProfilePicture.frag b/assets/shaders/engine/circleProfilePicture.frag
index 6cf0b2ab..1a641250 100644
--- a/assets/shaders/engine/circleProfilePicture.frag
+++ b/assets/shaders/engine/circleProfilePicture.frag
@@ -6,6 +6,6 @@ void main() {
float len = length(openfl_TextureCoordv - vec2(0.5, 0.5));
float r = 0.5 - (1.0 / openfl_TextureSize.x);
vec4 c = flixel_texture2D(bitmap, openfl_TextureCoordv);
- vec4 color = mix(vec4(0, 0, 0, 0.5), c, c.a);
- gl_FragColor = color * clamp(1 - ((len - r) * openfl_TextureSize.x), 0, 1);
+ vec4 color = mix(vec4(0.0, 0.0, 0.0, 0.5), c, c.a);
+ gl_FragColor = color * clamp(1.0 - ((len - r) * openfl_TextureSize.x), 0.0, 1.0);
}
\ No newline at end of file
diff --git a/assets/shaders/engine/editorBlur.frag b/assets/shaders/engine/editorBlur.frag
index 66b3eafb..ffcbc755 100644
--- a/assets/shaders/engine/editorBlur.frag
+++ b/assets/shaders/engine/editorBlur.frag
@@ -7,9 +7,9 @@ int steps = 16;
int stepsInside = 2;
float strength = 0.0075;
vec4 getColor(vec2 pos) {
- if (pos.x < 0) pos.x = 0;
+ if (pos.x < 0.0) pos.x = 0.0;
else if (pos.x > 1.0 - (1.0 / openfl_TextureSize.x)) pos.x = 1.0 - (1.0 / openfl_TextureSize.x);
- if (pos.y < 0) pos.y = 0;
+ if (pos.y < 0.0) pos.y = 0.0;
else if (pos.y > 1.0 - (1.0 / openfl_TextureSize.y)) pos.y = 1.0 - (1.0 / openfl_TextureSize.y);
// return textureCam(bitmap, pos);
return flixel_texture2D(bitmap, pos);
@@ -17,15 +17,18 @@ vec4 getColor(vec2 pos) {
void main() {
// vec2 camPos = getCamPos(openfl_TextureCoordv);
vec2 camPos = openfl_TextureCoordv;
- if (camPos.x < 0 || camPos.x > 1 || camPos.y < 0 || camPos.y > 1)
+ if (camPos.x < 0.0 || camPos.x > 1.0 || camPos.y < 0.0 || camPos.y > 1.0)
return;
vec4 color = getColor(camPos);
float fsteps = steps;
- for(float inside = 1; inside < stepsInside+1; inside++) {
+ for(float inside = 1.0; inside < stepsInside+1.0; inside++) {
for(int i = 0; i < steps; i++) {
float fi = i;
- color += getColor(camPos + vec2(strength * (inside / stepsInside) * cos(fi / fsteps * (PI * 2.0)), strength * (inside / stepsInside) * sin(fi / fsteps * (PI * 2.0))));
+ color += getColor(camPos + vec2(
+ strength * (inside / stepsInside) * cos(fi / fsteps * (PI * 2.0)),
+ strength * (inside / stepsInside) * sin(fi / fsteps * (PI * 2.0))
+ ));
}
}
diff --git a/assets/shaders/engine/editorWaveforms.frag b/assets/shaders/engine/editorWaveforms.frag
index 53fc9fdf..c2ea827d 100644
--- a/assets/shaders/engine/editorWaveforms.frag
+++ b/assets/shaders/engine/editorWaveforms.frag
@@ -32,70 +32,57 @@ float getAmplitude(vec2 pixel) {
return 0.0;
}
+float getAmpWidth(float amplitude) {
+ return (1.0-amplitude) * textureRes.x;
+}
+
bool inWaveForm(vec2 pixel, float width) {
- float widthdiv2 = width/2.;
+ float widthdiv2 = width/2.0;
return pixel.x > widthdiv2 && pixel.x < textureRes.x-widthdiv2;
}
+float getHightlight(float ampwidth) {
+ float remapCoord = (ampwidth/textureRes.x)/2.0;
+ float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.0-remapCoord, 0.0, 1.0);
+ return 1.0-(abs(mappedCoord-0.5)*2.0);
+}
+
+void outlineWaveform(vec2 pixel, vec2 offset) {
+ float amplitude = getAmplitude(pixel - offset);
+ float ampwidth = (1.0-amplitude) * textureRes.x;
+
+ if (!inWaveForm(pixel, ampwidth))
+ gl_FragColor -= outlinecolor*mix(0.5, 0.8, amplitude);
+}
+
void highDetailWaveform(vec2 pixel, float amplitude, float ampwidth) {
- if (inWaveForm(pixel, ampwidth)) {
- vec3 gradientColor = mix(gradient1, gradient2, openfl_TextureCoordv.x);
- gradientColor *= pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0;
+ vec3 gradientColor = mix(gradient1, gradient2, openfl_TextureCoordv.x);
+ gradientColor *= pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0;
+ gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(getHightlight(amplitude), 0.0, 1.0, 0.5, 1.0));
- float remapCoord = (amplitude/textureRes.x)/2.0;
+ float ampwidthHighlight = getAmpWidth(amplitude/3.0);
+ if (inWaveForm(pixel, ampwidthHighlight))
+ gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(getHightlight(ampwidthHighlight), 0.0, 1.0, 0.5, 1.0));
- float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.0-remapCoord, 0.0, 1.0);
- float hightlightAmount = 1.0-(abs(mappedCoord-0.5)*2.0);
+ gl_FragColor = vec4(vec3(gradientColor * mix(0.5, 0.8, amplitude))*openfl_Alphav, openfl_Alphav);
- gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(hightlightAmount, 0.0, 1.0, 0.5, 1.0));
-
- float ampwidthHighlight = (1.0-(amplitude*(1.0/3.0))) * textureRes.x;
- if (inWaveForm(pixel, ampwidthHighlight)) {
- float remapCoord = (ampwidthHighlight/textureRes.x)/2.0;
-
- float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.0-remapCoord, 0.0, 1.0);
- float hightlightAmount = 1.0-(abs(mappedCoord-0.5)*2.0);
-
- gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(hightlightAmount, 0.0, 1.0, 0.5, 1.0));
- }
-
- gl_FragColor = vec4(vec3(gradientColor * mix(0.5, 0.8, amplitude))*openfl_Alphav, openfl_Alphav);
-
- float lastAmplitude = getAmplitude(pixel - vec2(0.0, -1.0));
- float lastAmpwidth = (1.0-lastAmplitude) * textureRes.x;
-
- if (!inWaveForm(pixel, lastAmpwidth))
- gl_FragColor -= outlinecolor*mix(0.5, 0.8, amplitude);
-
- float nextAmplitude = getAmplitude(pixel - vec2(0.0, 1.0));
- float nextAmpwidth = (1.0-nextAmplitude) * textureRes.x;
-
- if (!inWaveForm(pixel, nextAmpwidth))
- gl_FragColor -= outlinecolor*mix(0.5, 0.8, amplitude);
-
- if (!inWaveForm(pixel, ampwidth+2.0) && amplitude > 0.0)
- gl_FragColor -= outlinecolor;
- }
+ outlineWaveform(pixel, vec2(0.0, -1.0));
+ outlineWaveform(pixel, vec2(0.0, 1.0));
}
void lowDetailWaveform(vec2 pixel, float amplitude, float ampwidth) {
- if (inWaveForm(pixel, ampwidth)) {
- vec3 color = lowdetailcol;
- color *= pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0;
-
- gl_FragColor = vec4(color, 1.0);
- }
+ gl_FragColor = vec4(lowdetailcol * (pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0), 1.0);
}
void main()
{
vec2 pixel = openfl_TextureCoordv * textureRes;
-
float amplitude = getAmplitude(pixel);
- float ampwidth = (1.0-amplitude) * textureRes.x;
+ float ampwidth = getAmpWidth(amplitude);
- if (lowDetail)
- lowDetailWaveform(pixel, amplitude, ampwidth);
- else
- highDetailWaveform(pixel, amplitude, ampwidth);
+ gl_FragColor = vec4(0.0);
+ if (!inWaveForm(pixel, ampwidth)) return;
+
+ if (lowDetail) lowDetailWaveform(pixel, amplitude, ampwidth);
+ else highDetailWaveform(pixel, amplitude, ampwidth);
}
\ No newline at end of file
diff --git a/assets/shaders/engine/updaterShader.frag b/assets/shaders/engine/updaterShader.frag
index f3a63166..ef6fec03 100644
--- a/assets/shaders/engine/updaterShader.frag
+++ b/assets/shaders/engine/updaterShader.frag
@@ -28,7 +28,7 @@ void main() {
hsv.g = (1.0/3.0) * strength * coords.y;
- hsv.r = mod(elapsed + coords.x + coords.y, 1);
+ hsv.r = mod(elapsed + coords.x + coords.y, 1.0);
gl_FragColor = vec4(hsv2rgb(hsv), color.a);
}
\ No newline at end of file
diff --git a/commandline/commands/Compiler.hx b/commandline/commands/Compiler.hx
index 62000723..fe64c198 100644
--- a/commandline/commands/Compiler.hx
+++ b/commandline/commands/Compiler.hx
@@ -20,7 +20,7 @@ class Compiler {
Sys.command("lime", arg);
}
- private static function getBuildTarget() {
+ public static function getBuildTarget() {
return switch(Sys.systemName()) {
case "Windows":
"windows";
diff --git a/commandline/commands/Update.hx b/commandline/commands/Update.hx
index d43c3620..92ae18c7 100644
--- a/commandline/commands/Update.hx
+++ b/commandline/commands/Update.hx
@@ -71,6 +71,18 @@ class Update {
}
}
}
+
+ // vswhere.exe its used to find any visual studio related installations on the system, including full visual studio ide installations, visual studio build tools installations, and other related components - Nex
+ if (Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -property catalog_productDisplayVersion').exitCode(true) == 1) {
+ prettyPrint("Installing Microsoft Visual Studio Community (Dependency)");
+ Sys.command("curl -# -O https://download.visualstudio.microsoft.com/download/pr/3105fcfe-e771-41d6-9a1c-fc971e7d03a7/8eb13958dc429a6e6f7e0d6704d43a55f18d02a253608351b6bf6723ffdaf24e/vs_Community.exe");
+ Sys.command("vs_Community.exe --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows10SDK.19041 -p");
+ FileSystem.deleteFile("vs_Community.exe");
+
+ prettyPrint('If it didn\'t say it before: Because of this component if you want to compile you have to restart the device.');
+ Sys.print("Do you wish to do it now [y/n]? ");
+ if(Sys.stdin().readLine().toLowerCase() == "y") Sys.command("shutdown /r /t 0 /f");
+ }
}
public static function prettyPrint(text:String) {
diff --git a/source/funkin/backend/chart/Chart.hx b/source/funkin/backend/chart/Chart.hx
index 0b5dffab..a1376e82 100644
--- a/source/funkin/backend/chart/Chart.hx
+++ b/source/funkin/backend/chart/Chart.hx
@@ -1,5 +1,6 @@
package funkin.backend.chart;
+import funkin.backend.system.Conductor;
import funkin.backend.chart.ChartData;
import flixel.util.FlxColor;
import haxe.io.Path;
@@ -143,7 +144,7 @@ class Chart {
base = data;
} else {
// base game chart
- BaseGameParser.parse(data, base);
+ FNFLegacyParser.parse(data, base);
}
#end
}
diff --git a/source/funkin/backend/chart/BaseGameParser.hx b/source/funkin/backend/chart/FNFLegacyParser.hx
similarity index 53%
rename from source/funkin/backend/chart/BaseGameParser.hx
rename to source/funkin/backend/chart/FNFLegacyParser.hx
index 9d017621..6f8faa00 100644
--- a/source/funkin/backend/chart/BaseGameParser.hx
+++ b/source/funkin/backend/chart/FNFLegacyParser.hx
@@ -1,6 +1,9 @@
package funkin.backend.chart;
-class BaseGameParser {
+import funkin.backend.chart.ChartData.ChartEvent;
+import funkin.backend.system.Conductor;
+
+class FNFLegacyParser {
public static function parse(data:Dynamic, result:ChartData) {
// base fnf chart parsing
var data:SwagSong = data;
@@ -109,7 +112,88 @@ class BaseGameParser {
curTime += curCrochet * beatsPerMeasure;
}
}
+
+ // have conductor set up BEFORE you run this :D -lunar
+ public static function encode(chart:ChartData):Dynamic {
+ var base:SwagSong = __convertToSwagSong(chart);
+ base.notes = __convertToSwagSections(chart);
+
+ for (strumLine in chart.strumLines)
+ for (note in strumLine.notes) {
+ var section:Int = Math.floor(Conductor.getStepForTime(note.time) / Conductor.getMeasureLength());
+ if (section > 0 && section < base.notes.length)
+ base.notes[section].sectionNotes.push([
+ note.time, // TIME
+ note.id + (strumLine.type == PLAYER ? 3 : 0), // DATA
+ note.sLen // SUSTAIN LENGTH
+ ]);
+ }
+
+ return {song: base};
+ }
+
+ // To make it easier to write the psych parser... -lunar
+ @:noCompletion public static function __convertToSwagSong(chart:ChartData):SwagSong {
+ var base:SwagSong = {
+ song: chart.meta.name,
+ notes: null,
+ bpm: chart.meta.bpm,
+ needsVoices: chart.meta.needsVoices,
+ speed: chart.scrollSpeed,
+
+ player1: null,
+ player2: null,
+ validScore: true
+ };
+
+ for (strumLine in chart.strumLines)
+ switch (strumLine.type) {
+ case OPPONENT:
+ if (base.player2 == null) base.player2 = strumLine.characters.getDefault(["dad"])[0];
+ case PLAYER:
+ if (base.player1 == null) base.player1 = strumLine.characters.getDefault(["bf"])[0];
+ case ADDITIONAL: // do nothing
+ }
+
+ return base;
+ }
+
+ @:noCompletion public static function __convertToSwagSections(chart:ChartData):Array {
+ var events:Array = chart.events.copy();
+
+ var measures:Float = Conductor.getMeasuresLength();
+ var sections:Int = Math.floor(measures) + (measures % 1 > 0 ? 1 : 0);
+
+ var notes:Array = cast new haxe.ds.Vector(sections);
+ for (section in 0...sections) {
+ var baseSection:SwagSection = {
+ sectionNotes: [],
+ lengthInSteps: Std.int(Conductor.getMeasureLength()),
+ mustHitSection: notes[section-1] != null ? notes[section-1].mustHitSection : false,
+ bpm: notes[section-1] != null ? notes[section-1].bpm : chart.meta.bpm,
+ changeBPM: false,
+ altAnim: notes[section-1] != null ? notes[section-1].altAnim : false
+ };
+
+ var sectionEndTime:Float = Conductor.getTimeForStep(Conductor.getMeasureLength() * (section+1));
+ while(events.length > 0 && events.last().time <= sectionEndTime) {
+ var event:ChartEvent = events.pop();
+ switch (event.name) {
+ case "Camera Movement":
+ baseSection.mustHitSection = chart.strumLines[event.params[0]].type == PLAYER;
+ case "Alt Animation Toggle":
+ baseSection.altAnim = event.params[0] || event.params[1];
+ case "BPM Change":
+ baseSection.changeBPM = true;
+ baseSection.bpm = event.params[0];
+ }
+ }
+ notes[section] = baseSection;
+ }
+ return notes;
+ }
}
+
typedef SwagSong =
{
var song:String;
@@ -117,13 +201,14 @@ typedef SwagSong =
var bpm:Float;
var needsVoices:Bool;
var speed:Float;
- var stage:String;
- var noteTypes:Array;
+ var ?stage:String;
+ var ?noteTypes:Array;
+ var ?events:Array;
var player1:String;
var player2:String;
- var gf:String;
- var gfVersion:String;
+ var ?gf:String;
+ var ?gfVersion:String;
var validScore:Bool;
// ADDITIONAL STUFF THAT MAY NOT BE PRESENT IN CHART
@@ -136,9 +221,12 @@ typedef SwagSection =
{
var sectionNotes:Array;
var lengthInSteps:Int;
+ var ?sectionBeats:Float;
+ var ?typeOfSection:Int;
var mustHitSection:Bool;
+ var ?gfSection:Bool;
var bpm:Float;
var changeBPM:Bool;
var altAnim:Null;
- @:optional var camTarget:Null;
+ var ?camTarget:Null;
}
diff --git a/source/funkin/backend/chart/PsychParser.hx b/source/funkin/backend/chart/PsychParser.hx
new file mode 100644
index 00000000..91f31a51
--- /dev/null
+++ b/source/funkin/backend/chart/PsychParser.hx
@@ -0,0 +1,92 @@
+package funkin.backend.chart;
+
+import funkin.backend.chart.ChartData.ChartEvent;
+import funkin.backend.chart.FNFLegacyParser.SwagSong;
+import funkin.backend.system.Conductor;
+
+class PsychParser {
+ public static function parse(data:Dynamic, result:ChartData)
+ FNFLegacyParser.parse(data, result);
+
+ public static function encode(chart:ChartData):Dynamic {
+ var base:SwagSong = FNFLegacyParser.__convertToSwagSong(chart);
+ base.notes = FNFLegacyParser.__convertToSwagSections(chart);
+ base.stage = chart.stage;
+
+ for (section in base.notes)
+ section.sectionBeats = Conductor.beatsPerMeasure;
+
+ for (strumLine in chart.strumLines)
+ if (strumLine.type == ADDITIONAL && base.gfVersion == null)
+ base.gfVersion = strumLine.characters.getDefault(["gf"])[0];
+
+ for (strumLine in chart.strumLines)
+ for (note in strumLine.notes) {
+ var section:Int = Math.floor(Conductor.getStepForTime(note.time) / Conductor.getMeasureLength());
+ if (section > 0 && section < base.notes.length)
+ base.notes[section].sectionNotes.push([
+ note.time, // TIME
+ note.id + (strumLine.type == PLAYER ? 3 : 0), // DATA
+ note.sLen, // SUSTAIN LENGTH
+ chart.noteTypes.getDefault([""])[note.type] // NOTE TYPE
+ ]);
+ }
+
+ base.events = [];
+
+ var groupedEvents:Array> = [];
+ var __last:Array = null;
+ var __lastTime:Float = Math.NaN;
+ for (e in chart.events) {
+ if (e == null) continue;
+ if (__last != null && __lastTime == e.time)
+ __last.push(e);
+ else {
+ __last = [e];
+ __lastTime = e.time;
+ groupedEvents.push(__last);
+ }
+ }
+
+ for (events in groupedEvents) {
+ var psychEvents:Array = [];
+ for (event in events)
+ switch (event.name) {
+ case "Add Camera Zoom":
+ psychEvents.push([
+ event.name,
+ event.params[1] == "camGame" ? event.params[0] : 0, // CAMERA ZOOM
+ event.params[1] == "camHUD" ? event.params[0] : 0, // UI ZOOM
+ ]);
+ case "Play Animation":
+ psychEvents.push([
+ event.name,
+ event.params[1], // ANIMATION TO PLAY
+ switch (chart.strumLines[event.params[0]].type) { // CHARACTER
+ case PLAYER: "bf";
+ case OPPONENT: "dad";
+ case ADDITIONAL: "gf";
+ }
+ ]);
+ case "Scroll Speed Change":
+ var eventStep:Float = Conductor.getStepForTime(event.time);
+ psychEvents.push([
+ "Change Scroll Speed",
+ event.params[1]/chart.scrollSpeed, // SCROLL SPEED MULTIPLER
+ Conductor.getTimeForStep(eventStep+event.params[2]) - Conductor.getTimeForStep(eventStep), // TIME
+ ]);
+ default:
+ // TODO: allow custom formats in event.json
+ var split:Float = event.params.length / 2;
+
+ var val1:String = [for (arg in 0...Math.ceil(split)) event.params[arg]].join(",");
+ var val2:String = [for (arg in Math.ceil(split)...event.params.length) event.params[arg]].join(",");
+
+ psychEvents.push([event.name, val1, val2]);
+ }
+ base.events.push([events[0].time, psychEvents]);
+ }
+
+ return {song: base};
+ }
+}
diff --git a/source/funkin/editors/DebugOptions.hx b/source/funkin/editors/DebugOptions.hx
index 01df41d0..8dcfeda7 100644
--- a/source/funkin/editors/DebugOptions.hx
+++ b/source/funkin/editors/DebugOptions.hx
@@ -36,9 +36,13 @@ class DebugOptionsScreen extends OptionsScreen {
}));
#end
add(new Checkbox(
- "Enable Editor SFXs",
+ "Editor SFXs",
"If checked, will play sound effects when working on editors (ex: will play sfxs when checking checkboxes...)",
"editorSFX"));
+ add(new Checkbox(
+ "Pretty Print",
+ "If checked, the saved files from the editor will be formatted to be easily viewable (does not apply to xmls...)",
+ "editorPrettyPrint"));
add(new Checkbox(
"Intensive Blur",
"If checked, will use more intensive blur that may be laggier but look better.",
diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx
index d7df2ab1..5226887e 100644
--- a/source/funkin/editors/charter/Charter.hx
+++ b/source/funkin/editors/charter/Charter.hx
@@ -1,5 +1,7 @@
package funkin.editors.charter;
+// ! FUCK YOU CHUF (your biggest fan -lunar) <3
+import flixel.input.FlxPointer;
import openfl.geom.Point;
import openfl.geom.Rectangle;
import flixel.graphics.FlxGraphic;
@@ -85,6 +87,7 @@ class Charter extends UIState {
public var uiCamera:FlxCamera;
public var selectionBox:UISliceSprite;
public var autoSaveNotif:CharterAutoSaveUI;
+ public static var autoSaveTimer:Float = 0;
public static var selection:Selection;
@@ -161,6 +164,15 @@ class Charter extends UIState {
onSelect: _file_meta_saveas,
},
null,
+ {
+ label: "Export As FNF Legacy...",
+ onSelect: _file_saveas_fnflegacy,
+ },
+ {
+ label: "Export As Psych Engine...",
+ onSelect: _file_saveas_psych,
+ },
+ null,
{
label: "Exit",
onSelect: _file_exit
@@ -491,6 +503,14 @@ class Charter extends UIState {
}
updateDisplaySprites();
+ // ! IF YOU EVER WANNA VIEW IN THE FUTURE, JUST USE A FLXSPRITE :D -lunar
+ /*var dataDisplay:FlxSprite = new FlxSprite().loadGraphic(waveformHandler.waveDatas.get("Voices.ogg"));
+ dataDisplay.scrollFactor.set(1, 0);
+ dataDisplay.scale.set(2, 2);
+ dataDisplay.updateHitbox();
+ dataDisplay.screenCenter(Y);
+ dataDisplay.cameras = [charterCamera]; dataDisplay.x = -dataDisplay.width; add(dataDisplay);*/
+
DiscordUtil.call("onEditorLoaded", ["Chart Editor", __song + " (" + __diff + ")"]);
}
@@ -568,8 +588,10 @@ class Charter extends UIState {
buildNoteTypesUI();
refreshBPMSensitive();
- // Undo Stuffs :D
- __relinkUndos();
+ // Just for now until i add event stacking -lunar
+ try {__relinkUndos();}
+ catch (e) {Logs.trace('Failed to relink undos: ${Std.string(e)}', ERROR);}
+
__applyPlaytestInfo();
}
@@ -669,7 +691,6 @@ class Charter extends UIState {
for(s in selection) s.selected = true;
}
- public static var autoSaveTimer:Float = 0;
var __autoSaveLocation:String = null;
public function updateAutoSaving(elapsed:Float) {
if (!Options.charterAutoSaves) return;
@@ -683,7 +704,6 @@ class Charter extends UIState {
'Saved chart at $__autoSaveLocation.json!'
);
}
-
if (autoSaveTimer <= 0) {
autoSaveTimer = Options.charterAutoSaveTime;
if (!autoSaveNotif.cancelled) {
@@ -691,9 +711,9 @@ class Charter extends UIState {
var songPath:String = '${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}';
if (Options.charterAutoSavesSeperateFolder)
- Chart.save(songPath, PlayState.SONG, __autoSaveLocation, {saveMetaInChart: false, folder: "autosaves"});
+ Chart.save(songPath, PlayState.SONG, __autoSaveLocation, {saveMetaInChart: false, folder: "autosaves", prettyPrint: Options.editorPrettyPrint});
else
- Chart.save(songPath, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false});
+ Chart.save(songPath, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, prettyPrint: Options.editorPrettyPrint});
undos.save();
}
autoSaveNotif.cancelled = false;
@@ -808,7 +828,7 @@ class Charter extends UIState {
FlxG.mouse.getWorldPosition(charterCamera, dragStartPos);
else if (FlxG.mouse.justPressedRight) {
closeCurrentContextMenu();
- gridActionType = DELTE_SELECTION;
+ gridActionType = DELETE_SELECTION;
}
if (gridBackdropDummy.hovered) {
@@ -888,7 +908,7 @@ class Charter extends UIState {
gridActionType = NONE;
currentCursor = ARROW;
}
- case DELTE_SELECTION:
+ case DELETE_SELECTION:
notesGroup.forEach(function(n) {
if (n.hovered || n.sustainDraggable) {
deletedNotes.push(n);
@@ -1275,7 +1295,7 @@ class Charter extends UIState {
}
function _file_saveas(_) {
- openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false)), {
+ openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false), null, Options.editorPrettyPrint ? "\t" : null), {
defaultSaveFile: '${__diff.toLowerCase()}.json'
}));
undos.save();
@@ -1291,7 +1311,7 @@ class Charter extends UIState {
}
function _file_saveas_no_events(_) {
- openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false)), {
+ openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false), null, Options.editorPrettyPrint ? "\t" : null), {
defaultSaveFile: '${__diff.toLowerCase()}.json'
}));
undos.save();
@@ -1314,11 +1334,23 @@ class Charter extends UIState {
}));
}
+ function _file_saveas_fnflegacy(_) {
+ openSubState(new SaveSubstate(Json.stringify(FNFLegacyParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), {
+ defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json',
+ }));
+ }
+
+ function _file_saveas_psych(_) {
+ openSubState(new SaveSubstate(Json.stringify(PsychParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), {
+ defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json',
+ }));
+ }
+
function _file_events_save(_) {
#if sys
CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/events.json',
- Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events})
+ Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null)
);
#else
_file_events_saveas(_);
@@ -1327,7 +1359,7 @@ class Charter extends UIState {
function _file_events_saveas(_) {
#if sys
- openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}), {
+ openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null), {
defaultSaveFile: 'events.json'
}));
#end
@@ -1336,7 +1368,7 @@ class Charter extends UIState {
#if sys
function saveTo(path:String, separateEvents:Bool = false) {
buildChart();
- Chart.save(path, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, saveEventsInChart: !separateEvents});
+ Chart.save(path, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, saveEventsInChart: !separateEvents, prettyPrint: Options.editorPrettyPrint});
}
#end
@@ -1962,7 +1994,7 @@ enum abstract CharterGridActionType(Int) {
var NOTE_DRAG = 2;
var INVALID_DRAG = 3;
var SUSTAIN_DRAG = 4;
- var DELTE_SELECTION = 5;
+ var DELETE_SELECTION = 5;
}
typedef PlaytestInfo = {
diff --git a/source/funkin/editors/charter/CharterAutoSaveUI.hx b/source/funkin/editors/charter/CharterAutoSaveUI.hx
index f23149d2..d412bc16 100644
--- a/source/funkin/editors/charter/CharterAutoSaveUI.hx
+++ b/source/funkin/editors/charter/CharterAutoSaveUI.hx
@@ -45,15 +45,16 @@ class CharterAutoSaveUI extends UISliceSprite {
icon.animation.curAnim.curFrame = 2;
(new FlxTimer()).start(1, (_) -> {disappearAnimation(true);});
- autosavingText.text += "(Canceled!)"; cancelButton.visible = false;
- for (member in [this, autosavingText]) member.color = 0xFFB62C2C;
- for (member in [progressBar, progressBarBack]) member.color = 0xFFE53D3D;
+ autosavingText.text += " (Canceled)!"; cancelButton.visible = false;
+ for (member in [this, autosavingText]) member.color = 0xFFE67F7F;
+ for (member in [progressBar, progressBarBack]) member.color = 0xFFE67F7F;
}, 24, 14);
cancelButton.frames = Paths.getFrames("editors/ui/grayscale-button");
cancelButton.color = 0xFFAC3D3D; cancelButton.alpha = 0.2;
- members.push(cancelButton);
+ members.push(cancelButton); cancelButton.visible = false;
cancelIcon = new FlxSprite(x-(10+16), y+8).loadGraphic(Paths.image("editors/autosave-delete"));
+ cancelIcon.color = 0xFFD60E0E;
members.push(cancelIcon);
alpha = 0;
diff --git a/source/funkin/editors/charter/CharterDeleteAnim.hx b/source/funkin/editors/charter/CharterDeleteAnim.hx
index 51a33eca..df3f565b 100644
--- a/source/funkin/editors/charter/CharterDeleteAnim.hx
+++ b/source/funkin/editors/charter/CharterDeleteAnim.hx
@@ -1,22 +1,57 @@
package funkin.editors.charter;
class CharterDeleteAnim extends CharterNote {
+ public var garbageIcon:FlxSprite;
+ public var garbageCircle:FlxSprite;
+
public var deleteNotes:Array<{note:CharterNote, time:Float}> = [];
public var deleteTime:Float = .4;
public function new() {
super();
- sustainSpr.color = 0xFF6D2425; color = 0xFF797171;
+ sustainSpr.color = 0xFF630000; color = 0xFF605A5A;
snappedToStrumline = selectable = autoAlpha = false;
@:privateAccess __animSpeed = 1.25;
+
+ garbageIcon = new FlxSprite().loadGraphic(Paths.image("editors/deleter"));
+ garbageIcon.color = 0xFF880000;
+ garbageIcon.cameras = [Charter.instance.uiCamera];
+
+ garbageCircle = new FlxSprite().loadGraphic(Paths.image("editors/deleter circle"));
+ garbageCircle.color = 0xFF880000; garbageCircle.alpha = .6;
+ garbageCircle.cameras = [Charter.instance.uiCamera];
}
+ var __garbageAlpha:Float = 0;
+ var __deletionTimer:Float = .1;
+ @:noCompletion var __mousePos:FlxPoint = FlxPoint.get();
public override function update(elapsed:Float) {
for (deleteData in deleteNotes) {
deleteData.time -= elapsed;
if (deleteData.time < 0) deleteNotes.remove(deleteData);
}
+
+ if (FlxG.mouse.justPressedRight) __deletionTimer = .1;
+ __deletionTimer -= elapsed;
+
+ __garbageAlpha = FlxMath.lerp(__garbageAlpha, FlxG.mouse.pressedRight && __deletionTimer <= 0 ? 1 : 0, 1/10);
+
+ FlxG.mouse.getWorldPosition(Charter.instance.uiCamera, __mousePos);
+ if (FlxG.mouse.pressedRight && __deletionTimer <= 0) {
+ garbageIcon.setPosition(
+ __mousePos.x + garbageIcon.width/2 + (.65*FlxG.random.float(-1, 1)) + 2,
+ __mousePos.y - garbageIcon.height + (.65*FlxG.random.float(-1, 1)) - 8
+ );
+
+ garbageCircle.setPosition(
+ __mousePos.x - garbageCircle.width/2,
+ (__mousePos.y - garbageCircle.height/2) + 2
+ );
+ }
+
+ garbageIcon.alpha = __garbageAlpha;
+ garbageCircle.alpha = __garbageAlpha*.6;
}
public override function draw() @:privateAccess {
@@ -39,5 +74,13 @@ class CharterDeleteAnim extends CharterNote {
super.draw();
}
+
+ if (garbageIcon.alpha > 0) garbageIcon.draw();
+ if (garbageCircle.alpha > 0) garbageCircle.draw();
+ }
+
+ public override function destroy() {
+ super.destroy();
+ __mousePos.put();
}
}
\ No newline at end of file
diff --git a/source/funkin/editors/charter/CharterStrumlineScreen.hx b/source/funkin/editors/charter/CharterStrumlineScreen.hx
index 3b8f7920..26696251 100644
--- a/source/funkin/editors/charter/CharterStrumlineScreen.hx
+++ b/source/funkin/editors/charter/CharterStrumlineScreen.hx
@@ -112,7 +112,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
var strOffset:Float = strumLine.strumLinePos == null ? (strumLine.type == 1 ? 0.75 : 0.25) : strumLine.strumLinePos;
- var startingPos:FlxPoint = strumLine.strumLinePos == null ?
+ var startingPos:FlxPoint = strumLine.strumPos == null ?
FlxPoint.get(strOffset, 50) :
FlxPoint.get(strOffset, strumLine.strumPos[1]);
diff --git a/source/funkin/editors/charter/CharterWaveformHandler.hx b/source/funkin/editors/charter/CharterWaveformHandler.hx
index ce4d9749..44ef5ee9 100644
--- a/source/funkin/editors/charter/CharterWaveformHandler.hx
+++ b/source/funkin/editors/charter/CharterWaveformHandler.hx
@@ -60,10 +60,6 @@ class CharterWaveformHandler extends FlxBasic {
waveDatas.set(name, waveData);
return waveData;
-
- // ! IF YOU EVER WANNA VIEW IN THE FUTURE, JUST USE A FLXSPRITE :D -lunar
- // var dataDisplay:FlxSprite = new FlxSprite().loadGraphic(waveformHandler.waveDatas.get("Voices.ogg"));
- // dataDisplay.cameras = [charterCamera]; dataDisplay.x = -dataDisplay.width; add(dataDisplay);
}
public function generateShader(name:String, sound:FlxSound):CustomShader {
diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx
index 91e977a6..2ae26370 100644
--- a/source/funkin/game/PlayState.hx
+++ b/source/funkin/game/PlayState.hx
@@ -759,7 +759,7 @@ class PlayState extends MusicBeatState
SaveWarning.warningFunc = saveWarn;
SaveWarning.saveFunc = () -> {
@:privateAccess Chart.save('${Paths.getAssetsRoot()}/songs/${Charter.__song.toLowerCase()}',
- PlayState.SONG, Charter.__diff.toLowerCase(), {saveMetaInChart: false, saveEventsInChart: true});
+ PlayState.SONG, Charter.__diff.toLowerCase(), {saveMetaInChart: false, saveEventsInChart: true, prettyPrint: Options.editorPrettyPrint});
}
}
}
diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx
index debe4a13..a9bf72ac 100644
--- a/source/funkin/options/Options.hx
+++ b/source/funkin/options/Options.hx
@@ -43,7 +43,7 @@ class Options
*/
public static var intensiveBlur:Bool = true;
public static var editorSFX:Bool = true;
- public static var resizableEditors:Bool = true;
+ public static var editorPrettyPrint:Bool = false;
public static var maxUndos:Int = 120;
/**