Merge branch 'main' into pr/397

This commit is contained in:
Ne_Eo
2025-01-10 16:33:08 +01:00
49 changed files with 560 additions and 162 deletions
+2 -1
View File
@@ -8,4 +8,5 @@ latest/windows/haxe/
.haxelib/
pages/
docs/doc.xml
mods/
mods/*
!mods/readme.txt
+3 -3
View File
@@ -41,9 +41,9 @@
- Reworked Lagless Credits Codename Engine's Contributors Menu
- New Credit Method for GitHub accounts (also lagless) in Mod Credits (First gets the data normally, if fails uses the ratelimited api)
- MANY OG GAME WEEK STUFF!! (still wip and softcoded and also many reworks by nex!)
- Senpai Cutscene got reworked! (https://github.com/FNF-CNE-Devs/CodenameEngine/assets/87421482/3b3f32fc-78d1-40fa-8398-776554cab1d6)
- Thorns got reworked with a cool chromatic aberration effect! (https://github.com/FNF-CNE-Devs/CodenameEngine/assets/87421482/73d9f7c5-1c9c-407e-baf0-e8e2c381ecbb)
- Winter Horrorland got reworked with a bloody vignette effect! (https://github.com/FNF-CNE-Devs/CodenameEngine/assets/87421482/1e10c3e2-32dc-4de2-b31a-d9d577d516da - https://github.com/FNF-CNE-Devs/CodenameEngine/assets/87421482/cad852c3-1ee2-409e-a70e-b3571ab5cf7b)
- Senpai Cutscene got reworked! (https://github.com/CodenameCrew/CodenameEngine/assets/87421482/3b3f32fc-78d1-40fa-8398-776554cab1d6)
- Thorns got reworked with a cool chromatic aberration effect! (https://github.com/CodenameCrew/CodenameEngine/assets/87421482/73d9f7c5-1c9c-407e-baf0-e8e2c381ecbb)
- Winter Horrorland got reworked with a bloody vignette effect! (https://github.com/CodenameCrew/CodenameEngine/assets/87421482/1e10c3e2-32dc-4de2-b31a-d9d577d516da - https://github.com/CodenameCrew/CodenameEngine/assets/87421482/cad852c3-1ee2-409e-a70e-b3571ab5cf7b)
- SMALLER BUT STILL COOL
- Ability to set Controls.hx variables (Being able to block inputs or even trigger them (needs to be in an if statement))
- You can now easily check if a cutscene was played (by default is disabled and makes it auto play or not; Check startCutscene() code for more details in PlayState)
+2 -2
View File
@@ -12,7 +12,7 @@ Also, the command `.\cne test` uses the source assets folder instead of the expo
## Codename Engine
Codename Engine is a new Friday Night Funkin' Engine aimed at simplifying modding, along with extensiblity and ease of use.<br>
### Before making issues or need help with something, check our website [HERE](https://fnf-cne-devs.github.io/) (it contains a wiki of how to mod with EXAMPLES, an api, lists of mods made with Codename Engine and more)!!!
### Before making issues or need help with something, check our website [HERE](https://codename-engine.com/) (it contains a wiki of how to mod with EXAMPLES, an api, lists of mods made with Codename Engine and more)!!!
#### The Engine includes many new features, as seen [here](FEATURES.md)<br>
#### Wanna see the new features added in the most recent update? Click [here](PATCHNOTES.md)<br>
@@ -67,7 +67,7 @@ In the future (when the engine won't be a WIP anymore) we're gonna also publish
- Download and play the engine with its mods and modpacks
- Mod and fork the engine (without using it for illicit purposes)
- Contribute to the engine (for example through *Pull Requests*, *Issues*, etc)
- Create a sub engine with Codename Engine as **TEMPLATE** with **CREDITS** (for example leaving the *credits menu submenu with the GitHub contributors* and putting the *[main devs](https://github.com/FNF-CNE-Devs)* in a *README* specifying that it's a *sub engine from Codename Engine*)
- Create a sub engine with Codename Engine as **TEMPLATE** with **CREDITS** (for example leaving the *credits menu submenu with the GitHub contributors* and putting the *[main devs](https://github.com/CodenameCrew)* in a *README* specifying that it's a *sub engine from Codename Engine*)
- Release excutable mods that use Codename Engine as source (Specifing that uses Codename Engine by for example the same way written above this)
- Release modpacks
+2 -2
View File
@@ -1,8 +1,8 @@
@ECHO OFF
cd ..
echo Building Game...
lime build windows --haxeflag="--macro include('scripting')" --haxeflag="-xml docs/doc.xml" -D DOCUMENTATION --no-output
lime build windows --haxeflag="-xml docs/doc.xml" -D doc-gen -D DOCUMENTATION --no-output
echo art
echo Generated the api xml file at docs/doc.xml
echo Please put this in FNF-CNE-Devs.github.io/api-generator/api/doc.xml
echo Please put this in codename-website/api-generator/api/doc.xml
+4 -8
View File
@@ -92,15 +92,11 @@ function update(elapsed) {
if (!canDoShit) return;
var oldSec = curSelected;
if (controls.DOWN_P)
changeSelection(1, false);
if (controls.UP_P)
changeSelection(-1);
if (oldSec != curSelected) {
changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0) - FlxG.mouse.wheel);
if (oldSec != curSelected)
FlxG.sound.play(Paths.sound(isThorns ? 'pixel/type' : 'pixel/pixelText'));
}
if (controls.ACCEPT) {
FlxG.sound.play(Paths.sound(isThorns ? 'pixel/ANGRY' : 'pixel/clickText'));
@@ -118,7 +114,7 @@ function update(elapsed) {
}
}
function changeSelection(change) {
function changeSelection(change) { // this overrides the function inside of the normal pause btw, so no event gets called - Nex
curSelected += change;
if (curSelected < 0)
+4 -4
View File
@@ -77,17 +77,17 @@ class Update {
if (curHaxeVer[i] < requiredHaxeVer[i]) {
prettyPrint("!! WARNING !!");
Sys.println("Your current Haxe version is outdated.");
Sys.println('You\'re using ${haxeVer}, while the required version is 4.2.5.');
Sys.println('You\'re using ${haxeVer}, while the minimum required version is 4.2.5.');
Sys.println('The engine may not compile with your current version of Haxe.');
Sys.println('We recommend upgrading to 4.2.5');
Sys.println('We recommend upgrading to 4.2.5 or newer');
break;
} else if (curHaxeVer[i] > requiredHaxeVer[i]) {
}/* else if (curHaxeVer[i] > requiredHaxeVer[i]) {
prettyPrint("!! WARNING !!"
+ "\nUsing Haxe 4.3.0 and above is currently not recommended due to lack of testing.");
Sys.println('');
Sys.println('We recommend downgrading back to 4.2.5.');
break;
}
}*/
}
}
+7 -7
View File
@@ -5,17 +5,17 @@
<lib name="lime" version="8.1.2" />
<!-- Flixel -->
<git name="flixel" url="https://github.com/FNF-CNE-Devs/flixel" />
<git name="flixel-addons" url="https://github.com/FNF-CNE-Devs/flixel-addons" />
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" />
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" />
<!-- Other Libraries -->
<git name="hscript-improved" url="https://github.com/FNF-CNE-Devs/hscript-improved" ref="custom-classes" />
<git name="flxanimate" url="https://github.com/FNF-CNE-Devs/flxanimate" />
<git name="hxdiscord_rpc" url="https://github.com/FNF-CNE-Devs/hxdiscord_rpc" />
<lib name="hxvlc" skipDeps="true" />
<git name="hscript-improved" url="https://github.com/CodenameCrew/hscript-improved" ref="custom-classes" />
<git name="flxanimate" url="https://github.com/CodenameCrew/cne-flxanimate" />
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" />
<lib name="hxvlc" version="1.9.3" skipDeps="true" />
<!-- Documentation and other features -->
<git name="away3d" url="https://github.com/FNF-CNE-Devs/away3d" />
<git name="away3d" url="https://github.com/CodenameCrew/away3d" />
<!-- <lib name="dox" /> -->
<lib name="format" />
<lib name="markdown" />
+8 -3
View File
@@ -7,14 +7,19 @@ import flixel.math.FlxAngle;
import flixel.math.FlxRect;
import flixel.graphics.frames.FlxFrame;
import flixel.math.FlxPoint;
import openfl.display.BlendMode;
class FlxAnimate extends flxanimate.FlxAnimate {
static var rMatrix = new FlxMatrix();
override function drawLimb(limb:FlxFrame, _rMatrix:FlxMatrix, ?colorTransform:ColorTransform)
override function drawLimb(limb:FlxFrame, _rMatrix:FlxMatrix, ?colorTransform:ColorTransform, ?blendMode:BlendMode)
{
if (alpha == 0 || colorTransform != null && (colorTransform.alphaMultiplier == 0 || colorTransform.alphaOffset == -255) || limb == null || limb.type == EMPTY)
return;
if (blendMode == null)
blendMode = BlendMode.NORMAL;
for (camera in cameras)
{
rMatrix.identity();
@@ -69,7 +74,7 @@ class FlxAnimate extends flxanimate.FlxAnimate {
}
rMatrix.translate(_point.x, _point.y);
camera.drawPixels(limb, null, rMatrix, colorTransform, blend, antialiasing, shaderEnabled ? shader : null);
camera.drawPixels(limb, null, rMatrix, colorTransform, blendMode, antialiasing, shaderEnabled ? shader : null);
#if FLX_DEBUG
FlxBasic.visibleCount++;
#end
@@ -87,4 +92,4 @@ class FlxAnimate extends flxanimate.FlxAnimate {
// TODO: ACTUAL OPTIMISATION
return true;
}
}
}
+35 -12
View File
@@ -22,9 +22,9 @@ enum abstract XMLAnimType(Int)
var BEAT = 1;
var LOOP = 2;
public static function fromString(str:String, def:XMLAnimType = NONE)
public static function fromString(str:String, def:XMLAnimType = XMLAnimType.NONE)
{
return switch (str.trim().toLowerCase())
return switch (StringTools.trim(str).toLowerCase())
{
case "none": NONE;
case "beat" | "onbeat": BEAT;
@@ -328,7 +328,31 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
lastAnimContext = Context;
}
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation> {
public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE)
{
return XMLUtil.addAnimToSprite(this, {
name: name,
anim: prefix,
fps: frameRate,
loop: looped == null ? animType == LOOP : looped,
animType: animType,
x: x,
y: y,
indices: indices,
forced: forced
});
}
public inline function removeAnim(name:String)
{
if (animateAtlas != null)
@:privateAccess animateAtlas.anim.animsMap.remove(name);
else
animation.remove(name);
}
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation>
{
if(animateAtlas != null)
return animateAtlas.anim.getByName(name);
return animation.getByName(name);
@@ -341,7 +365,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return FlxPoint.weak(0, 0);
}
public inline function hasAnimation(AnimName:String):Bool @:privateAccess
public inline function hasAnim(AnimName:String):Bool @:privateAccess
return animateAtlas != null ? (animateAtlas.anim.animsMap.exists(AnimName)
|| animateAtlas.anim.symbolDictionary.exists(AnimName)) : animation.exists(AnimName);
@@ -364,13 +388,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
}
public inline function removeAnimation(name:String) {
if (animateAtlas != null)
@:privateAccess animateAtlas.anim.animsMap.remove(name);
else
animation.remove(name);
}
public inline function getNameList():Array<String> {
if (animateAtlas != null)
return [for (name in @:privateAccess animateAtlas.anim.animsMap.keys()) name];
@@ -378,7 +395,8 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return animation.getNameList();
}
public inline function stopAnimation() {
public inline function stopAnim()
{
if (animateAtlas != null)
animateAtlas.anim.pause();
else
@@ -393,6 +411,11 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public inline function isAnimAtEnd() {
return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
}
// Backwards compat (the names used to be all different and it sucked, please lets use the same format in the future) - Nex
public inline function hasAnimation(AnimName:String) return hasAnim(AnimName);
public inline function removeAnimation(name:String) return removeAnim(name);
public inline function stopAnimation() return stopAnim();
#end
// Getter / Setters
+9 -1
View File
@@ -93,6 +93,9 @@ class MusicBeatState extends FlxState implements IBeatReceiver
public var scriptsAllowed:Bool = true;
public static var lastScriptName:String = null;
public static var lastStateName:String = null;
public var scriptName:String = null;
public static var skipTransOut:Bool = false;
@@ -108,7 +111,12 @@ class MusicBeatState extends FlxState implements IBeatReceiver
public function new(scriptsAllowed:Bool = true, ?scriptName:String) {
super();
this.scriptsAllowed = #if SOFTCODED_STATES scriptsAllowed #else false #end;
this.scriptName = scriptName;
if(lastStateName != (lastStateName = Type.getClassName(Type.getClass(this)))) {
lastScriptName = null;
}
this.scriptName = scriptName != null ? scriptName : lastScriptName;
lastScriptName = this.scriptName;
}
function loadScript() {
+55 -14
View File
@@ -1,15 +1,24 @@
package funkin.backend;
import funkin.backend.scripting.events.CancellableEvent;
import funkin.backend.scripting.events.TransitionCreationEvent;
import funkin.backend.scripting.Script;
import flixel.tweens.FlxTween;
import flixel.FlxState;
import funkin.backend.utils.FunkinParentDisabler;
class MusicBeatTransition extends MusicBeatSubstate {
public static var script:String = "";
public var transitionScript:Script;
var nextFrameSkip:Bool = false;
public var transitionTween:FlxTween = null;
public var transitionCamera:FlxCamera;
public var newState:FlxState;
public var transOut:Bool = false;
public var allowSkip:Bool = true;
public var blackSpr:FlxSprite;
public var transitionSprite:FunkinSprite;
@@ -20,16 +29,30 @@ class MusicBeatTransition extends MusicBeatSubstate {
public override function create() {
if (newState != null)
add(new FunkinParentDisabler(true));
add(new FunkinParentDisabler(true, false));
transitionCamera = new FlxCamera();
transitionCamera.bgColor = 0;
FlxG.cameras.add(transitionCamera, false);
cameras = [transitionCamera];
var out = newState != null;
blackSpr = new FlxSprite(0, out ? -transitionCamera.height : transitionCamera.height).makeGraphic(1, 1, -1);
transitionScript = Script.create(Paths.script(script));
transitionScript.setParent(this);
transitionScript.load();
var event = EventManager.get(TransitionCreationEvent).recycle(newState != null, newState);
transitionScript.call('create', [event]);
transOut = event.transOut;
newState = event.newState;
if (event.cancelled) {
super.create();
return;
}
blackSpr = new FlxSprite(0, transOut ? -transitionCamera.height : transitionCamera.height).makeGraphic(1, 1, -1);
blackSpr.scale.set(transitionCamera.width, transitionCamera.height);
blackSpr.color = 0xFF000000;
blackSpr.updateHitbox();
@@ -43,7 +66,7 @@ class MusicBeatTransition extends MusicBeatSubstate {
} else {
transitionSprite.screenCenter();
}
transitionCamera.flipY = !out;
transitionCamera.flipY = !transOut;
add(transitionSprite);
transitionCamera.scroll.y = transitionCamera.height;
@@ -55,41 +78,59 @@ class MusicBeatTransition extends MusicBeatSubstate {
});
super.create();
transitionScript.call('postCreate', [event]);
}
public override function update(elapsed:Float) {
transitionScript.call('update', [elapsed]);
super.update(elapsed);
if (nextFrameSkip) {
finish();
return;
var event = new CancellableEvent();
transitionScript.call('onSkip', [event]);
if (!event.cancelled) {
finish();
return;
}
}
if (!parent.persistentUpdate && FlxG.keys.pressed.SHIFT) {
if (allowSkip && !parent.persistentUpdate && FlxG.keys.pressed.SHIFT) {
// skip
if (newState != null) {
nextFrameSkip = true;
parent.persistentDraw = false;
} else {
finish();
var event = new CancellableEvent();
transitionScript.call('onSkip', [event]);
if (!event.cancelled) {
finish();
}
}
}
transitionScript.call('postUpdate', [elapsed]);
}
public function finish() {
var event = new CancellableEvent();
transitionScript.call('onFinish', [event]);
if (event.cancelled) return;
if (newState != null)
FlxG.switchState(newState);
close();
transitionScript.call('onPostFinish');
}
public override function destroy() {
if (transitionTween != null)
transitionTween.cancel();
transitionScript.call('destroy');
if (transitionTween != null) transitionTween.cancel();
transitionTween = FlxDestroyUtil.destroy(transitionTween);
if (newState == null && FlxG.cameras.list.contains(transitionCamera))
FlxG.cameras.remove(transitionCamera);
else
transitionCamera.bgColor = 0xFF000000;
if (newState == null && FlxG.cameras.list.contains(transitionCamera)) FlxG.cameras.remove(transitionCamera);
else transitionCamera.bgColor = 0xFF000000;
transitionScript.destroy();
super.destroy();
}
}
+7 -2
View File
@@ -93,7 +93,12 @@ class ModsFolder {
public static function getModsList():Array<String> {
var mods:Array<String> = [];
#if MOD_SUPPORT
for(modFolder in FileSystem.readDirectory(modsPath)) {
final modsList:Array<String> = FileSystem.readDirectory(modsPath);
if (modsList == null || modsList.length <= 0)
return mods;
for (modFolder in modsList) {
if (FileSystem.isDirectory('${modsPath}${modFolder}')) {
mods.push(modFolder);
} else {
@@ -159,4 +164,4 @@ class ModsFolder {
return prepareModLibrary(libName, new ZipFolderLibrary(zipPath, libName, modName), force);
}
#end
}
}
+78 -27
View File
@@ -1,6 +1,5 @@
package funkin.backend.chart;
import funkin.backend.system.Conductor;
import funkin.backend.chart.ChartData;
import flixel.util.FlxColor;
import haxe.io.Path;
@@ -13,12 +12,68 @@ import sys.FileSystem;
using StringTools;
enum abstract ChartFormat(Int) {
var CODENAME = 0;
var LEGACY = 1; // also used by many other engines (old Psych, Kade and more) - Nex
var VSLICE = 2;
var PSYCH_NEW = 3;
@:to public function toString():String {
return switch(cast (this, ChartFormat)) {
case CODENAME: "CODENAME";
case LEGACY: "LEGACY";
case VSLICE: "VSLICE";
case PSYCH_NEW: "PSYCH_NEW";
}
}
public static function fromString(str:String, def:ChartFormat = ChartFormat.LEGACY) {
str = str.toLowerCase();
str = StringTools.replace(str, " ", "");
str = StringTools.replace(str, "_", "");
str = StringTools.replace(str, ".", "");
if(StringTools.startsWith(str, "psychv1") || StringTools.startsWith(str, "psych1"))
return PSYCH_NEW;
return switch(str) {
case "codename" | "codenameengine": CODENAME;
case "newpsych" | "psychnew": PSYCH_NEW;
default: def;
}
}
}
class Chart {
/**
* Default background colors for songs without bg color
*/
public inline static var defaultColor:FlxColor = 0xFF9271FD;
public static function cleanSongData(data:Dynamic):Dynamic {
if (Reflect.hasField(data, "song")) {
var field:Dynamic = Reflect.field(data, "song");
if (field != null && Type.typeof(field) == TObject) // Cant use Reflect.isObject, because it detects strings for some reason
return field;
}
return data;
}
public static function detectChartFormat(data:Dynamic):ChartFormat {
var __temp:Dynamic; // imma reuse this var so the program doesnt have to get values multiple times - Nex
if ((__temp = data.codenameChart) == true || __temp == "true")
return CODENAME;
if (Reflect.hasField(data, "version") && Reflect.hasField(data, "scrollSpeed"))
return VSLICE;
if ((__temp = cleanSongData(data).format) != null && __temp is String && StringTools.startsWith(__temp, "psych_v1"))
return PSYCH_NEW;
return LEGACY;
}
public static function loadEventsJson(songName:String) {
var path = Paths.file('songs/${songName.toLowerCase()}/events.json');
var data:Array<ChartEvent> = null;
@@ -33,8 +88,9 @@ class Chart {
}
public static function loadChartMeta(songName:String, difficulty:String = "normal", fromMods:Bool = true) {
var metaPath = Paths.file('songs/${songName.toLowerCase()}/meta.json');
var metaDiffPath = Paths.file('songs/${songName.toLowerCase()}/meta-${difficulty.toLowerCase()}.json');
var songNameLower = songName.toLowerCase();
var metaPath = Paths.file('songs/${songNameLower}/meta.json');
var metaDiffPath = Paths.file('songs/${songNameLower}/meta-${difficulty.toLowerCase()}.json');
var data:ChartMetaData = null;
var fromMods:Bool = fromMods;
@@ -67,7 +123,7 @@ class Chart {
data.setFieldDefault("parsedColor", data.color.getColorFromDynamic().getDefault(defaultColor));
if (data.difficulties.length <= 0) {
data.difficulties = [for(f in Paths.getFolderContent('songs/${songName.toLowerCase()}/charts/', false, !fromMods)) if (Path.extension(f = f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
data.difficulties = [for(f in Paths.getFolderContent('songs/${songNameLower}/charts/', false, !fromMods)) if (Path.extension(f = f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
if (data.difficulties.length == 3) {
var hasHard = false, hasNormal = false, hasEasy = false;
for(d in data.difficulties) {
@@ -116,12 +172,12 @@ class Chart {
Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED);
}
if (data != null) {
/**
* CHART CONVERSION
*/
#if REGION
if (Reflect.hasField(data, "codenameChart") && Reflect.field(data, "codenameChart") == true) {
/**
* CHART CONVERSION
*/
#if REGION
if (data != null) switch (detectChartFormat(data)) {
case CODENAME:
// backward compat on events since its caused problems
var eventTypesToString:Map<Int, String> = [
-1 => "HScript Call",
@@ -132,28 +188,23 @@ class Chart {
];
if (data.events == null) data.events = [];
for (event in cast(data.events, Array<Dynamic>)) {
if (Reflect.hasField(event, "type")) {
if(event.type != null)
event.name = eventTypesToString[event.type];
Reflect.deleteField(event, "type");
}
for (event in cast(data.events, Array<Dynamic>)) if (Reflect.hasField(event, "type")) {
if (event.type != null)
event.name = eventTypesToString[event.type];
Reflect.deleteField(event, "type");
}
// codename chart
base = data;
} else {
// base game chart
FNFLegacyParser.parse(data, base);
}
#end
case PSYCH_NEW: PsychParser.parse(data, base);
case VSLICE: // TODO
case LEGACY: FNFLegacyParser.parse(data, base);
}
#end
if (base.meta == null)
base.meta = loadChartMeta(songName, difficulty, base.fromMods);
var loadedMeta = loadChartMeta(songName, difficulty, base.fromMods);
if (base.meta == null) base.meta = loadedMeta;
else {
var loadedMeta = loadChartMeta(songName, difficulty, base.fromMods);
for(field in Reflect.fields(base.meta)) {
for (field in Reflect.fields(base.meta)) {
var f = Reflect.field(base.meta, field);
if (f != null)
Reflect.setField(loadedMeta, field, f);
@@ -249,4 +300,4 @@ typedef ChartSaveSettings = {
var ?saveEventsInChart:Bool;
var ?prettyPrint:Bool;
var ?folder:String;
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ class EventsData {
{name: "Time (Steps)", type: TFloat(0.25, 9999, 0.25, 2), defValue: 4},
{name: "Camera", type: TDropDown(['camGame', 'camHUD']), defValue: "camHUD"}
],
"BPM Change" => [{name: "Target BPM", type: TFloat(1), defValue: 100}],
"BPM Change" => [{name: "Target BPM", type: TFloat(1.00, null, 0.001, 3), defValue: 100}],
"Scroll Speed Change" => [
{name: "Tween Speed?", type: TBool, defValue: true},
{name: "New Speed", type: TFloat(0.01, 99, 0.01, 2), defValue: 1.},
@@ -6,12 +6,7 @@ import funkin.backend.system.Conductor;
class FNFLegacyParser {
public static function parse(data:Dynamic, result:ChartData) {
// base fnf chart parsing
var data:SwagSong = data;
if (Reflect.hasField(data, "song")) {
var field:Dynamic = Reflect.field(data, "song");
if (!(field is String))
data = field;
}
var data:SwagSong = Chart.cleanSongData(data);
result.scrollSpeed = data.speed;
result.stage = data.stage;
@@ -29,7 +24,7 @@ class FNFLegacyParser {
position: "boyfriend",
notes: []
});
var gfName = data.gf != null ? data.gf : (data.gfVersion != null ? data.gfVersion : "gf");
var gfName = data.gf != null ? data.gf : (data.gfVersion != null ? data.gfVersion : (data.player3 != null ? data.player3 : "gf"));
if (!p2isGF && gfName != "none") {
result.strumLines.push({
characters: [gfName],
@@ -142,10 +137,10 @@ class FNFLegacyParser {
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
(!swagSection.mustHitSection && strumLine.type == PLAYER))
sectionNote[1] += 4;
swagSection.sectionNotes.push(sectionNote);
swagSection.sectionNotes.push(sectionNote);
}
}
return {song: base};
}
@@ -227,6 +222,7 @@ typedef SwagSong =
var player1:String;
var player2:String;
var ?player3:String; // alt for gf but idr if it was just used in psych or what but eh whatever maybe its better here anyways - Nex
var ?gf:String;
var ?gfVersion:String;
var validScore:Bool;
+25 -7
View File
@@ -6,15 +6,33 @@ import funkin.backend.chart.FNFLegacyParser.SwagSong;
import funkin.backend.system.Conductor;
class PsychParser {
// Alreadly parsed in sections
// Already parsed in sections
public static var ignoreEvents:Array<String> = [
"Camera Movement",
"Alt Animation Toggle",
"BPM Change"
];
public static function parse(data:Dynamic, result:ChartData)
/**
* Converts 1.0 Psych charts to older ones
*/
public static function standardize(data:Dynamic, result:ChartData) {
var sectionsData:Array<Dynamic> = Chart.cleanSongData(data).notes;
if (sectionsData == null) return;
for (section in sectionsData) for (note in cast(section.sectionNotes, Array<Dynamic>)) {
var gottaHitNote:Bool = section.mustHitSection == (note[1] >= 4);
note[1] = (note[1] % 4) + (gottaHitNote ? 4 : 0);
if (note[3] != null && Std.isOfType(note[3], String))
note[3] = Chart.addNoteType(result, note[3]);
}
}
public static function parse(data:Dynamic, result:ChartData) {
if (Chart.detectChartFormat(data) == PSYCH_NEW) standardize(data, result);
FNFLegacyParser.parse(data, result);
}
public static function encode(chart:ChartData):Dynamic {
var base:SwagSong = FNFLegacyParser.__convertToSwagSong(chart);
@@ -32,7 +50,7 @@ class PsychParser {
for (note in strumLine.notes) {
var section:Int = Math.floor(Conductor.getStepForTime(note.time) / Conductor.getMeasureLength());
var swagSection:SwagSection = base.notes[section];
if (section >= 0 && section < base.notes.length) {
var sectionNote:Array<Dynamic> = [
note.time, // TIME
@@ -44,10 +62,10 @@ class PsychParser {
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
(!swagSection.mustHitSection && strumLine.type == PLAYER))
sectionNote[1] += 4;
swagSection.sectionNotes.push(sectionNote);
swagSection.sectionNotes.push(sectionNote);
}
}
var groupedEvents:Array<Array<ChartEvent>> = [];
var __last:Array<ChartEvent> = null;
var __lastTime:Float = Math.NaN;
@@ -91,7 +109,7 @@ class PsychParser {
FlxMath.roundDecimal(event.params[1]/chart.scrollSpeed, 2), // SCROLL SPEED MULTIPLER
FlxMath.roundDecimal( // TIME
event.params[0] ? // IS TWEENED?
(Conductor.getTimeForStep(eventStep+event.params[2]) - Conductor.getTimeForStep(eventStep))/1000
(Conductor.getTimeForStep(eventStep+event.params[2]) - Conductor.getTimeForStep(eventStep))/1000
: 0, 2)
]);
default:
@@ -106,7 +124,7 @@ class PsychParser {
for (psychEvent in psychEvents)
for (i in 1...3) // Turn both vals into strings
if (!(psychEvent[i] is String))
if (!(psychEvent[i] is String))
psychEvent[i] = Std.string(psychEvent[i]);
base.events.push([events[0].time, psychEvents]);
+3 -1
View File
@@ -74,8 +74,10 @@ class HScript extends Script {
var code = Assets.getText(p);
var expr:Expr = null;
try {
if (code != null && code.trim() != "")
if (code != null && code.trim() != "") {
parser.line = 1; // fun fact: this is all you need to reuse a parser without issues. all the other vars get reset on parse.
expr = parser.parseString(code, cl.join("/") + "." + hxExt);
}
} catch(e:Error) {
_errorHandler(e);
} catch(e) {
@@ -0,0 +1,18 @@
package funkin.backend.scripting.events;
import flixel.FlxState;
/**
* CANCEL this event to prevent default behaviour!
*/
final class TransitionCreationEvent extends CancellableEvent {
/**
* If the transition is going out into another state
*/
public var transOut:Bool;
/**
* The state that is about to be loaded (only on trans out)
*/
public var newState:FlxState;
}
+37 -1
View File
@@ -192,7 +192,11 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
if(value == null)
value = ShaderTemplates.defaultVertexSource;
glRawVertexSource = value;
value = value.replace("#pragma header", ShaderTemplates.vertHeader).replace("#pragma body", ShaderTemplates.vertBody);
var useBackCompat:Bool = true;
for (regex in ShaderTemplates.vertBackCompatVarList) if (!regex.match(value)) useBackCompat = false;
value = value.replace("#pragma header", useBackCompat ? ShaderTemplates.vertHeaderBackCompat : ShaderTemplates.vertHeader).replace("#pragma body", useBackCompat ? ShaderTemplates.vertBodyBackCompat : ShaderTemplates.vertBody);
if (value != __glVertexSource)
{
__glSourceDirty = true;
@@ -625,6 +629,38 @@ if(hasColorTransform) {
gl_Position = openfl_Matrix * openfl_Position;";
// TODO: make this ignore comments
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;";
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
openfl_ColorMultiplierv = openfl_ColorMultiplier;
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
}
gl_Position = openfl_Matrix * openfl_Position;";
public static final defaultVertexSource:String = "#pragma header
+17
View File
@@ -49,6 +49,10 @@ class Main extends Sprite
public static var game:FunkinGame;
/**
* The time since the game was focused last time in seconds.
*/
public static var timeSinceFocus(get, never):Float;
public static var time:Int = 0;
// You can pretty much ignore everything from here on - your code should go in your states.
@@ -152,10 +156,14 @@ class Main extends Sprite
Conductor.init();
AudioSwitchFix.init();
EventManager.init();
FlxG.signals.focusGained.add(onFocus);
FlxG.signals.preStateSwitch.add(onStateSwitch);
FlxG.signals.postStateSwitch.add(onStateSwitchPost);
FlxG.mouse.useSystemCursor = true;
#if DARK_MODE_WINDOW
if(funkin.backend.utils.NativeAPI.hasVersion("Windows 10")) funkin.backend.utils.NativeAPI.redrawWindowHeader();
#end
ModsFolder.init();
#if MOD_SUPPORT
@@ -187,6 +195,10 @@ class Main extends Sprite
{asset: diamond, width: 32, height: 32}, new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
}
public static function onFocus() {
_tickFocused = FlxG.game.ticks;
}
private static function onStateSwitch() {
scaleMode.resetSize();
}
@@ -206,4 +218,9 @@ class Main extends Sprite
MemoryUtil.clearMajor();
}
private static var _tickFocused:Float = 0;
public static function get_timeSinceFocus():Float {
return (FlxG.game.ticks - _tickFocused) / 1000;
}
}
@@ -53,6 +53,7 @@ class MainState extends FlxState {
}
#end
MusicBeatTransition.script = "";
Main.refreshAssets();
ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder);
DiscordUtil.init();
@@ -1,16 +1,17 @@
package funkin.backend.system.macros;
#if macro
@:dox(hide)
class NewHaxeWarning {
public static function warn() {
#if (haxe >= "4.3.0")
/*#if (haxe >= "4.3.0")
Sys.println("====================");
Sys.println("[ WARNING ]");
Sys.println("Compiling with Haxe 4.3.0 isnt fully recommended yet, but it does work.");
Sys.println("We recommend building the project using Haxe 4.2.5.");
Sys.println("You can download it here -> https://haxe.org/download/version/4.2.5/");
Sys.println("====================");
#end
#end*/
}
}
#end
+1 -1
View File
@@ -4,7 +4,7 @@ import flixel.sound.FlxSound;
import lime.media.AudioBuffer;
// Thank you yosh :DDD -lunar
// (https://github.com/FNF-CNE-Devs/YoshiCrafterEngine/blob/main/source/WaveformSprite.hx)
// (https://github.com/CodenameCrew/YoshiCrafterEngine/blob/main/source/WaveformSprite.hx)
class AudioAnalyzer {
public var buffer:AudioBuffer;
var __peakByte:Float = 0;
@@ -19,9 +19,11 @@ class FunkinParentDisabler extends FlxBasic {
var __timers:Array<FlxTimer>;
var __sounds:Array<FlxSound>;
var __replaceUponDestroy:Bool;
public function new(replaceUponDestroy:Bool = false) {
var __restoreUponDestroy:Bool;
public function new(replaceUponDestroy:Bool = false, restoreUponDestroy:Bool = true) {
super();
__replaceUponDestroy = replaceUponDestroy;
__restoreUponDestroy = restoreUponDestroy;
@:privateAccess {
// tweens
__tweens = FlxTween.globalManager._tweens.copy();
@@ -53,6 +55,11 @@ class FunkinParentDisabler extends FlxBasic {
public override function destroy() {
super.destroy();
@:privateAccess {
if (!__restoreUponDestroy) {
for(t in __tweens) { t.cancel(); t.destroy(); };
for(t in __timers) { t.cancel(); t.destroy(); };
return;
}
if (__replaceUponDestroy) {
FlxTween.globalManager._tweens = __tweens;
FlxTimer.globalManager._timers = __timers;
+75
View File
@@ -3,6 +3,7 @@ package funkin.backend.utils;
import funkin.backend.utils.native.*;
import flixel.util.typeLimit.OneOfTwo;
import flixel.util.typeLimit.OneOfThree;
import flixel.util.FlxColor;
/**
* Class for functions that talk to a lower level than haxe, such as message boxes, and more.
@@ -84,12 +85,86 @@ class NativeAPI {
#end
}
/**
* WINDOW COLOR MODE FUNCTIONS.
*/
/**
* Switch the window's color mode to dark or light mode.
*/
public static function setDarkMode(title:String, enable:Bool) {
#if windows
if(title == null) title = lime.app.Application.current.window.title;
Windows.setDarkMode(title, enable);
#end
}
/**
* Switch the window's color to any color.
*
* WARNING: This is exclusive to windows 11 users, unfortunately.
*
* NOTE: Setting the color to 0x00000000 (FlxColor.TRANSPARENT) will set the border (must have setBorder on) invisible.
*/
public static function setWindowBorderColor(title:String, color:FlxColor, setHeader:Bool = true, setBorder:Bool = true) {
#if windows
if(title == null) title = lime.app.Application.current.window.title;
Windows.setWindowBorderColor(title, [color.red, color.green, color.blue, color.alpha], setHeader, setBorder);
#end
}
/**
* Resets the window's border color to the default one.
*
* WARNING: This is exclusive to windows 11 users, unfortunately.
**/
public static function resetWindowBorderColor(title:String, setHeader:Bool = true, setBorder:Bool = true) {
#if windows
if(title == null) title = lime.app.Application.current.window.title;
Windows.setWindowBorderColor(title, [-1, -1, -1, -1], setHeader, setBorder);
#end
}
/**
* Switch the window's title text to any color.
*
* WARNING: This is exclusive to windows 11 users, unfortunately.
*/
public static function setWindowTitleColor(title:String, color:FlxColor) {
#if windows
if(title == null) title = lime.app.Application.current.window.title;
Windows.setWindowTitleColor(title, [color.red, color.green, color.blue, color.alpha]);
#end
}
/**
* Resets the window's title color to the default one.
*
* WARNING: This is exclusive to windows 11 users, unfortunately.
**/
public static function resetWindowTitleColor(title:String) {
#if windows
if(title == null) title = lime.app.Application.current.window.title;
Windows.setWindowTitleColor(title, [-1, -1, -1, -1]);
#end
}
/**
* Forces the window header to redraw, causes a small visual jitter so use it sparingly.
*/
public static function redrawWindowHeader() {
#if windows
flixel.FlxG.stage.window.borderless = true;
flixel.FlxG.stage.window.borderless = false;
#end
}
/**
* Can be used to check if your using a specific version of an OS (or if your using a certain OS).
*/
public static function hasVersion(vers:String)
return lime.system.System.platformLabel.toLowerCase().indexOf(vers.toLowerCase()) != -1;
/**
* Shows a message box
*/
+21 -20
View File
@@ -143,6 +143,8 @@ class XMLUtil {
var graphicSizey:Null<Int> = Std.parseInt(node.att.graphicSizey);
if (graphicSizey.isNotNull()) spr.setGraphicSize(0, graphicSizey);
}
if (node.has.flipX) spr.flipX = node.att.flipX == "true";
if (node.has.flipY) spr.flipY = node.att.flipY == "true";
if (node.has.updateHitbox && node.att.updateHitbox == "true") spr.updateHitbox();
if (node.has.zoomfactor)
@@ -164,19 +166,17 @@ class XMLUtil {
if(node.hasNode.anim) {
for(anim in node.nodes.anim)
addXMLAnimation(spr, anim);
} else {
if (spr.frames != null && spr.frames.frames != null) {
addAnimToSprite(spr, {
name: "idle",
anim: null,
fps: 24,
loop: spr.spriteAnimType == LOOP,
animType: spr.spriteAnimType,
x: 0,
y: 0,
indices: [for(i in 0...spr.frames.frames.length) i]
});
}
} else if (spr.frames != null && spr.frames.frames != null) {
addAnimToSprite(spr, {
name: "idle",
anim: null,
fps: 24,
loop: spr.spriteAnimType == LOOP,
animType: spr.spriteAnimType,
x: 0,
y: 0,
indices: [for(i in 0...spr.frames.frames.length) i]
});
}
return spr;
@@ -238,16 +238,17 @@ class XMLUtil {
if(animData.anim == null)
return MISSING_PROPERTY;
if (animData.indices.length > 0)
if (animData.indices != null && animData.indices.length > 0)
animateAnim.addBySymbolIndices(animData.name, animData.anim, animData.indices, animData.fps, animData.loop);
else
animateAnim.addBySymbol(animData.name, animData.anim, animData.fps, animData.loop);
} else {
if (animData.anim == null && animData.indices.length > 0)
sprite.animation.add(animData.name, animData.indices, animData.fps, animData.loop);
else if (animData.indices.length > 0)
sprite.animation.addByIndices(animData.name, animData.anim, animData.indices, "", animData.fps, animData.loop);
else
if (animData.indices != null && animData.indices.length > 0) {
if (animData.anim == null)
sprite.animation.add(animData.name, animData.indices, animData.fps, animData.loop);
else
sprite.animation.addByIndices(animData.name, animData.anim, animData.indices, "", animData.fps, animData.loop);
} else
sprite.animation.addByPrefix(animData.name, animData.anim, animData.fps, animData.loop);
}
@@ -393,4 +394,4 @@ typedef BeatAnim = {
interface IXMLEvents {
public function onPropertySet(property:String, value:Dynamic):Void;
}
}
+45 -1
View File
@@ -134,13 +134,57 @@ class Windows {
HWND window = FindWindowA(NULL, title.c_str());
// Look for child windows if top level aint found
if (window == NULL) window = FindWindowExA(GetActiveWindow(), NULL, NULL, title.c_str());
// If still not found, try to get the active window
if (window == NULL) window = GetActiveWindow();
if (window == NULL) return;
if (window != NULL && S_OK != DwmSetWindowAttribute(window, 19, &darkMode, sizeof(darkMode))) {
if (S_OK != DwmSetWindowAttribute(window, 19, &darkMode, sizeof(darkMode))) {
DwmSetWindowAttribute(window, 20, &darkMode, sizeof(darkMode));
}
UpdateWindow(window);
')
public static function setDarkMode(title:String, enable:Bool) {}
@:functionCode('
HWND window = FindWindowA(NULL, title.c_str());
if (window == NULL) window = FindWindowExA(GetActiveWindow(), NULL, NULL, title.c_str());
if (window == NULL) window = GetActiveWindow();
if (window == NULL) return;
COLORREF finalColor;
if(color[0] == -1 && color[1] == -1 && color[2] == -1 && color[3] == -1) { // bad fix, I know :sob:
finalColor = 0xFFFFFFFF; // Default border
} else if(color[3] == 0) {
finalColor = 0xFFFFFFFE; // No border (must have setBorder as true)
} else {
finalColor = RGB(color[0], color[1], color[2]); // Use your custom color
}
if(setHeader) DwmSetWindowAttribute(window, 35, &finalColor, sizeof(COLORREF));
if(setBorder) DwmSetWindowAttribute(window, 34, &finalColor, sizeof(COLORREF));
UpdateWindow(window);
')
public static function setWindowBorderColor(title:String, color:Array<Int>, setHeader:Bool = true, setBorder:Bool = true) {}
@:functionCode('
HWND window = FindWindowA(NULL, title.c_str());
if (window == NULL) window = FindWindowExA(GetActiveWindow(), NULL, NULL, title.c_str());
if (window == NULL) window = GetActiveWindow();
if (window == NULL) return;
COLORREF finalColor;
if(color[0] == -1 && color[1] == -1 && color[2] == -1 && color[3] == -1) { // bad fix, I know :sob:
finalColor = 0xFFFFFFFF; // Default border
} else {
finalColor = RGB(color[0], color[1], color[2]); // Use your custom color
}
DwmSetWindowAttribute(window, 36, &finalColor, sizeof(COLORREF));
UpdateWindow(window);
')
public static function setWindowTitleColor(title:String, color:Array<Int>) {}
@:functionCode('
// https://stackoverflow.com/questions/15543571/allocconsole-not-displaying-cout
+3 -1
View File
@@ -22,11 +22,13 @@ class EditorPicker extends MusicBeatSubstate {
iconID: 2,
state: null
},
#if debug
{
name: "UI Debug State",
iconID: 3,
state: UIDebugState
},
#end
{
name: "Debug Options",
iconID: 4,
@@ -214,4 +216,4 @@ class EditorPickerOption extends FlxTypedSpriteGroup<FlxSprite> {
callback();
});
}
}
}
@@ -23,6 +23,7 @@ class ChartDataScreen extends UISubstateWindow {
public override function create() {
FlxG.sound.music.pause();
Charter.instance.vocals.pause();
for (strumLine in Charter.instance.strumLines.members) strumLine.vocals.pause();
winTitle = 'Chart Properties';
winWidth = 420; winHeight = 230; // guys look, the funny numbers!
+31 -1
View File
@@ -341,6 +341,7 @@ class Charter extends UIState {
null,
{
label: "↑ Speed 25%",
keybind: [PERIOD],
onSelect: _playback_speed_raise
},
{
@@ -349,6 +350,7 @@ class Charter extends UIState {
},
{
label: "↓ Speed 25%",
keybind: [COMMA],
onSelect: _playback_speed_lower
},
null,
@@ -362,6 +364,22 @@ class Charter extends UIState {
keybind: [D],
onSelect: _playback_forward
},
{
label: "Go to start of section",
keybind: [SHIFT, S],
onSelect: _playback_section_start
},
null,
{
label: "Go back a step",
keybind: [W],
onSelect: _playback_back_step
},
{
label: "Go forward a step",
keybind: [S],
onSelect: _playback_forward_step
},
null,
{
label: "Metronome",
@@ -1338,7 +1356,7 @@ class Charter extends UIState {
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',
@@ -1579,6 +1597,18 @@ class Charter extends UIState {
if (FlxG.sound.music.playing) return;
Conductor.songPosition += (Conductor.beatsPerMeasure * __crochet);
}
function _playback_section_start(_) {
if(FlxG.sound.music.playing) return;
Conductor.songPosition = (Conductor.beatsPerMeasure * (60000 / Conductor.bpm)) * curMeasure;
}
function _playback_back_step(_) {
if (FlxG.sound.music.playing) return;
Conductor.songPosition -= Conductor.stepCrochet;
}
function _playback_forward_step(_) {
if (FlxG.sound.music.playing) return;
Conductor.songPosition += Conductor.stepCrochet;
}
function _song_start(_) {
if (FlxG.sound.music.playing) return;
Conductor.songPosition = 0;
@@ -44,6 +44,7 @@ class CharterEventScreen extends UISubstateWindow {
FlxG.sound.music.pause(); // prevent the song from continuing
Charter.instance.vocals.pause();
for (strumLine in Charter.instance.strumLines.members) strumLine.vocals.pause();
events = chartEvent.events.copy();
@@ -40,6 +40,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
FlxG.sound.music.pause();
Charter.instance.vocals.pause();
for (strumLine in Charter.instance.strumLines.members) strumLine.vocals.pause();
function addLabelOn(ui:UISprite, text:String)
add(new UIText(ui.x, ui.y - 24, 0, text));
+1 -1
View File
@@ -76,7 +76,7 @@ class CharterNote extends UISprite implements ICharterSelectable {
public function updatePos(step:Float, id:Int, susLength:Float = 0, ?type:Int = 0, ?strumLine:CharterStrumline = null) {
this.step = step;
this.id = id;
this.susLength = susLength;
this.susLength = Math.max(susLength, 0);
this.type = type;
if (strumLine != null) this.strumLine = strumLine;
@@ -13,6 +13,7 @@ class CharterNoteTypesList extends UISubstateWindow {
public override function create() {
FlxG.sound.music.pause();
Charter.instance.vocals.pause();
for (strumLine in Charter.instance.strumLines.members) strumLine.vocals.pause();
winTitle = 'Note Types List Editor';
winWidth = 380; winHeight = 390;
@@ -52,6 +52,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
FlxG.sound.music.pause();
Charter.instance.vocals.pause();
for (strumLine in Charter.instance.strumLines.members) strumLine.vocals.pause();
super.create();
+1
View File
@@ -26,6 +26,7 @@ class UISlider extends UISprite {
public var value(default, set):Float = 0;
public function set_value(newVal:Float):Float {
newVal = FlxMath.bound(newVal, segments[0].start, segments[segments.length-1].end);
__barProgress = __calcProgress(newVal); if (onChange != null) onChange(newVal);
if (valueStepper != null) valueStepper.value = newVal;
return value = newVal;
+15 -6
View File
@@ -119,12 +119,21 @@ class UITextBox extends UISliceSprite implements IUIFocusable {
case END:
position = label.text.length;
case V:
if (modifier == KeyModifier.LEFT_CTRL || modifier == KeyModifier.RIGHT_CTRL) {
// paste
var data:String = Clipboard.generalClipboard.getData(TEXT_FORMAT);
if (data != null)
onTextInput(data);
}
// Hey lj here, fixed copying because before we checked if the modifier was left or right ctrl
// but somehow it gave a int outside of the KeyModifier's range :sob:
// apparently there is a boolean that just checks for you. yw :D
// if we are not holding ctrl, ignore
if (!modifier.ctrlKey) return;
// we pasting
var data:String = Clipboard.generalClipboard.getData(TEXT_FORMAT);
if (data != null) onTextInput(data);
case C:
// if we are not holding ctrl, ignore
if (!modifier.ctrlKey) return;
// copying
Clipboard.generalClipboard.setData(TEXT_FORMAT, label.text);
default:
// nothing
}
+1 -1
View File
@@ -686,7 +686,7 @@ class PlayState extends MusicBeatState
startingPos,
strumLine.strumScale == null ? 1 : strumLine.strumScale,
strumLine.type == 2 || (!coopMode && !((strumLine.type == 1 && !opponentMode) || (strumLine.type == 0 && opponentMode))),
strumLine.type != 1, coopMode ? (strumLine.type == 1 ? controlsP1 : controlsP2) : controls,
strumLine.type != 1, coopMode ? ((strumLine.type == 1) != opponentMode ? controlsP1 : controlsP2) : controls,
strumLine.vocalsSuffix
);
strLine.cameras = [camHUD];
+1
View File
@@ -292,6 +292,7 @@ class StrumLine extends FlxTypedGroup<Strum> {
super.destroy();
if(startingPos != null)
startingPos.put();
notes = FlxDestroyUtil.destroy(notes);
}
/**
+7 -2
View File
@@ -2,6 +2,7 @@ package funkin.menus;
import funkin.backend.chart.Chart;
import funkin.backend.chart.ChartData.ChartMetaData;
import funkin.backend.system.Conductor;
import haxe.io.Path;
import openfl.text.TextField;
import flixel.text.FlxText;
@@ -216,7 +217,7 @@ class FreeplayState extends MusicBeatState
lerpScore = intendedScore;
if (canSelect) {
changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0));
changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0) - FlxG.mouse.wheel);
changeDiff((controls.LEFT_P ? -1 : 0) + (controls.RIGHT_P ? 1 : 0));
changeCoopMode((FlxG.keys.justPressed.TAB ? 1 : 0));
// putting it before so that its actually smooth
@@ -239,7 +240,11 @@ class FreeplayState extends MusicBeatState
autoplayElapsed += elapsed;
if (!disableAutoPlay && !songInstPlaying && (autoplayElapsed > timeUntilAutoplay || FlxG.keys.justPressed.SPACE)) {
if (curPlayingInst != (curPlayingInst = Paths.inst(songs[curSelected].name, songs[curSelected].difficulties[curDifficulty]))) {
var huh:Void->Void = function() FlxG.sound.playMusic(curPlayingInst, 0);
var huh:Void->Void = function()
{
FlxG.sound.playMusic(curPlayingInst, 0);
Conductor.changeBPM(songs[curSelected].bpm, songs[curSelected].beatsPerMeasure, songs[curSelected].stepsPerBeat);
}
if(!disableAsyncLoading) Main.execAsync(huh);
else huh();
}
+5 -6
View File
@@ -109,11 +109,12 @@ class MainMenuState extends MusicBeatState
*/
}
if (controls.UP_P)
changeItem(-1);
var upP = controls.UP_P;
var downP = controls.DOWN_P;
var scroll = FlxG.mouse.wheel;
if (controls.DOWN_P)
changeItem(1);
if (upP || downP || scroll != 0) // like this we wont break mods that expect a 0 change event when calling sometimes - Nex
changeItem((upP ? -1 : 0) + (downP ? 1 : 0) - scroll);
if (controls.BACK)
FlxG.switchState(new TitleState());
@@ -127,9 +128,7 @@ class MainMenuState extends MusicBeatState
#end
if (controls.ACCEPT)
{
selectItem();
}
}
super.update(elapsed);
+2 -2
View File
@@ -39,7 +39,7 @@ class ModSwitchMenu extends MusicBeatSubstate {
public override function update(elapsed:Float) {
super.update(elapsed);
changeSelection((controls.DOWN_P ? 1 : 0) + (controls.UP_P ? -1 : 0));
changeSelection((controls.DOWN_P ? 1 : 0) + (controls.UP_P ? -1 : 0) - FlxG.mouse.wheel);
if (controls.ACCEPT) {
ModsFolder.switchMod(mods[curSelected]);
@@ -64,4 +64,4 @@ class ModSwitchMenu extends MusicBeatSubstate {
alphabets.members[curSelected].alpha = 1;
}
}
#end
#end
+5 -6
View File
@@ -124,13 +124,12 @@ class PauseSubState extends MusicBeatSubstate
var upP = controls.UP_P;
var downP = controls.DOWN_P;
var accepted = controls.ACCEPT;
var scroll = FlxG.mouse.wheel;
if (upP)
changeSelection(-1);
if (downP)
changeSelection(1);
if (accepted)
if (upP || downP || scroll != 0) // like this we wont break mods that expect a 0 change event when calling sometimes - Nex
changeSelection((upP ? -1 : 0) + (downP ? 1 : 0) - scroll);
if (controls.ACCEPT)
selectOption();
}
+1 -1
View File
@@ -142,7 +142,7 @@ class StoryMenuState extends MusicBeatState {
}
changeDifficulty((controls.LEFT_P ? -1 : 0) + (controls.RIGHT_P ? 1 : 0));
changeWeek((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0));
changeWeek((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0) - FlxG.mouse.wheel);
if (controls.ACCEPT)
selectWeek();
@@ -10,7 +10,7 @@ using StringTools;
class CreditsCodename extends funkin.options.OptionsScreen {
public var error:Bool = false;
public var author:String = "FNF-CNE-Devs";
public var author:String = "CodenameCrew";
public var totalContributions:Int = 0;
public var mainDevCol:FlxColor = 0xFF9C35D5;
+1 -1
View File
@@ -11,7 +11,7 @@ class CreditsMain extends TreeMenu {
var items:Array<OptionType> = [];
public override function create() {
bg = new FlxSprite(-80).loadGraphic(Paths.image('menus/menuBGBlue'));
bg = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue'));
// bg.scrollFactor.set();
bg.scale.set(1.15, 1.15);
bg.updateHitbox();
+3 -1
View File
@@ -31,6 +31,8 @@ class OptionsMenu extends TreeMenu {
}
];
var bg:FlxSprite;
public override function create() {
super.create();
@@ -38,7 +40,7 @@ class OptionsMenu extends TreeMenu {
DiscordUtil.call("onMenuLoaded", ["Options Menu"]);
var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue'));
bg = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue'));
// bg.scrollFactor.set();
bg.scale.set(1.15, 1.15);
bg.updateHitbox();
+1 -1
View File
@@ -45,7 +45,7 @@ class OptionsScreen extends FlxTypedSpriteGroup<OptionType> {
if (members.length > 0) {
members[curSelected].selected = true;
if (controls.ACCEPT || FlxG.mouse.justReleased)
if (controls.ACCEPT || (FlxG.mouse.justReleased && Main.timeSinceFocus > 0.25))
members[curSelected].onSelect();
if (controls.LEFT_P)
members[curSelected].onChangeSelection(-1);
-1
View File
@@ -29,7 +29,6 @@ class Config {
];
public static final DISALLOW_ABSTRACT_AND_ENUM = [
"funkin.backend.FunkinSprite", // Error: String has no field trim, Due to Func
"funkin.backend.scripting.events.PlayAnimEvent", // Error: expected member name or ';' after declaration specifiers, Due to Func
];
}