Merge branch 'main' into pr/397
This commit is contained in:
+2
-1
@@ -8,4 +8,5 @@ latest/windows/haxe/
|
||||
.haxelib/
|
||||
pages/
|
||||
docs/doc.xml
|
||||
mods/
|
||||
mods/*
|
||||
!mods/readme.txt
|
||||
|
||||
+3
-3
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -292,6 +292,7 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
super.destroy();
|
||||
if(startingPos != null)
|
||||
startingPos.put();
|
||||
notes = FlxDestroyUtil.destroy(notes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user