Merge branch 'main' into base-fnf-port-remake

This commit is contained in:
⍚~Nex
2024-10-21 17:50:30 +02:00
38 changed files with 328 additions and 164 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
function postHide() {
if(curTween != null) {
if(animation.curAnim?.name == 'angry-show') curTween.cancel();
if(getAnimName() == 'angry-show') curTween.cancel();
else curTween.percent = 1;
}
}
}
+1 -1
View File
@@ -87,7 +87,7 @@ class Flx3DCamera extends FlxCamera {
default: new OBJParser();
}, (event:Asset3DEvent) -> {
if (event.asset != null && event.asset.assetType == Asset3DType.MESH) {
var mesh:Mesh = cast(event.asset, Mesh);
var mesh:Mesh = cast event.asset;
if (material != null)
mesh.material = material;
meshes.push(mesh);
+1 -1
View File
@@ -60,7 +60,7 @@ class Flx3DView extends FlxView3D {
default: new OBJParser();
}, (event:Asset3DEvent) -> {
if (event.asset != null && event.asset.assetType == Asset3DType.MESH) {
var mesh:Mesh = cast(event.asset, Mesh);
var mesh:Mesh = cast event.asset;
if (material != null)
mesh.material = material;
meshes.push(mesh);
+14 -1
View File
@@ -1,10 +1,13 @@
package funkin.backend;
import flixel.addons.effects.FlxSkewedSprite;
import flixel.animation.FlxAnimation;
import flixel.math.FlxMatrix;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.util.typeLimit.OneOfTwo;
import flxanimate.animate.FlxAnim.FlxSymbolAnimation;
import funkin.backend.scripting.events.PlayAnimContext;
import funkin.backend.system.interfaces.IBeatReceiver;
import funkin.backend.system.interfaces.IOffsetCompatible;
@@ -327,6 +330,12 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
lastAnimContext = Context;
}
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation> {
if(animateAtlas != null)
return animateAtlas.anim.getByName(name);
return animation.getByName(name);
}
public inline function getAnimOffset(name:String)
{
if (animOffsets.exists(name))
@@ -368,7 +377,11 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
}
public inline function isAnimFinished() {
return animateAtlas != null ? (animateAtlas.anim.finished) : (animation.curAnim != null ? animation.curAnim.finished : true);
return animateAtlas != null ? animateAtlas.anim.finished : (animation.curAnim != null ? animation.curAnim.finished : true);
}
public inline function isAnimAtEnd() {
return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
}
#end
+3 -3
View File
@@ -4,12 +4,12 @@ import funkin.backend.system.interfaces.IBeatReceiver;
class MusicBeatGroup extends FlxTypedSpriteGroup<FlxSprite> implements IBeatReceiver {
public function beatHit(curBeat:Int) {
for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat);
for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver = cast e;_;}).beatHit(curBeat);
}
public function stepHit(curStep:Int) {
for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep);
for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver = cast e;_;}).stepHit(curStep);
}
public function measureHit(curMeasure:Int) {
for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure);
for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver = cast e;_;}).measureHit(curMeasure);
}
}
+6 -5
View File
@@ -192,19 +192,19 @@ class MusicBeatState extends FlxState implements IBeatReceiver
@:dox(hide) public function stepHit(curStep:Int):Void
{
for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep);
for(e in members) if (e != null && e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).stepHit(curStep);
call("stepHit", [curStep]);
}
@:dox(hide) public function beatHit(curBeat:Int):Void
{
for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat);
for(e in members) if (e != null && e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).beatHit(curBeat);
call("beatHit", [curBeat]);
}
@:dox(hide) public function measureHit(curMeasure:Int):Void
{
for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure);
for(e in members) if (e != null && e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).measureHit(curMeasure);
call("measureHit", [curMeasure]);
}
@@ -276,8 +276,9 @@ class MusicBeatState extends FlxState implements IBeatReceiver
public override function resetSubState() {
super.resetSubState();
if (subState != null && subState is MusicBeatSubstate) {
cast(subState, MusicBeatSubstate).parent = this;
cast(subState, MusicBeatSubstate).onSubstateOpen();
var subState:MusicBeatSubstate = cast subState;
subState.parent = this;
subState.onSubstateOpen();
}
}
}
+5 -4
View File
@@ -181,19 +181,19 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
@:dox(hide) public function stepHit(curStep:Int):Void
{
for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep);
for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).stepHit(curStep);
call("stepHit", [curStep]);
}
@:dox(hide) public function beatHit(curBeat:Int):Void
{
for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat);
for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).beatHit(curBeat);
call("beatHit", [curBeat]);
}
@:dox(hide) public function measureHit(curMeasure:Int):Void
{
for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure);
for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).measureHit(curMeasure);
call("measureHit", [curMeasure]);
}
@@ -256,7 +256,8 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
public override function resetSubState() {
if (subState != null && subState is MusicBeatSubstate) {
cast(subState, MusicBeatSubstate).parent = this;
var subState:MusicBeatSubstate = cast subState;
subState.parent = this;
super.resetSubState();
if (subState != null)
cast(subState, MusicBeatSubstate).onSubstateOpen();
+15 -3
View File
@@ -110,18 +110,30 @@ class Paths
return scriptPath;
}
static public function chart(song:String, ?difficulty:String):String {
static public function chart(song:String, ?difficulty:String):String
{
difficulty = (difficulty != null ? difficulty : Constants.DEFAULT_DIFFICULTY).toLowerCase();
song = song.toLowerCase();
return getPath('songs/$song/charts/$difficulty.json', null);
}
static public function character(character:String):String {
inline static public function character(character:String):String
{
return getPath('data/characters/$character.xml', null);
}
inline static public function font(key:String) {
/**
* Gets the name of a registered font.
* @param font The font's path (if it's already passed as a font name, the same name will be returned)
*/
inline static public function getFontName(font:String)
{
return OpenFlAssets.exists(font, FONT) ? OpenFlAssets.getFont(font).fontName : font;
}
inline static public function font(key:String)
{
return getPath('fonts/$key');
}
@@ -33,8 +33,8 @@ class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBe
if (parentScript != null) {
if (script is HScript && parentScript is HScript) {
var hscript = cast(script, HScript);
var parentHScript = cast(parentScript, HScript);
var hscript:HScript = cast script;
var parentHScript:HScript = cast parentScript;
hscript.interp.variables = parentHScript.interp.variables;
hscript.interp.publicVariables = parentHScript.interp.publicVariables;
@@ -0,0 +1,21 @@
package funkin.backend.scripting.events;
import funkin.game.Character;
import haxe.xml.Access;
final class CharacterNodeEvent extends CancellableEvent {
/**
* The character instance
*/
public var character:Character;
/**
* The node which is currently being parsed
*/
public var node:Access;
/**
* The name of the node, quicker access than e.node.name
*/
public var name:String;
}
@@ -0,0 +1,16 @@
package funkin.backend.scripting.events;
import funkin.game.Character;
import haxe.xml.Access;
final class CharacterXMLEvent extends CancellableEvent {
/**
* The character instance
*/
public var character:Character;
/**
* The xml
*/
public var xml:Access;
}
+6 -2
View File
@@ -181,7 +181,11 @@ class Conductor
private static var __updateMeasure:Bool;
private static function update() {
if (FlxG.state != null && FlxG.state is MusicBeatState && cast(FlxG.state, MusicBeatState).cancelConductorUpdate) return;
if (FlxG.state != null && FlxG.state is MusicBeatState) {
var state:MusicBeatState = cast FlxG.state;
if(state.cancelConductorUpdate)
return;
}
__updateSongPos(FlxG.elapsed);
@@ -233,7 +237,7 @@ class Conductor
var state = FlxG.state;
while(state != null) {
if (state is IBeatReceiver && (state.subState == null || state.persistentUpdate)) {
var st = cast(state, IBeatReceiver);
var st:IBeatReceiver = cast state;
if (curStep > oldStep) {
for(i in oldStep...curStep) {
st.stepHit(i+1);
+6 -7
View File
@@ -30,9 +30,9 @@ class Flags {
var splitContent = [for(e in data.split("\n")) if ((trimmed = e.trim()) != "") trimmed];
for(line in splitContent) {
if (line.startsWith(";")) continue;
if (line.startsWith("#")) continue;
if (line.startsWith("//")) continue;
if(line.startsWith(";")) continue;
if(line.startsWith("#")) continue;
if(line.startsWith("//")) continue;
if(line.length == 0) continue;
if(line.charAt(0) == "[" && line.charAt(line.length-1) == "]") continue;
@@ -41,10 +41,9 @@ class Flags {
var name = line.substr(0, index).trim();
var value = line.substr(index+1).trim();
if (value.length > 1 && value.charCodeAt(0) == '"'.code && value.charCodeAt(value.length-1) == '"'.code)
value = value.substr(1, value.length - 2);
if (value.length == 0 || name.length == 0)
var wasQuoted = value.length > 1 && value.charCodeAt(0) == '"'.code && value.charCodeAt(value.length-1) == '"'.code;
if(wasQuoted) value = value.substr(1, value.length - 2);
if((!wasQuoted && value.length == 0) || name.length == 0)
continue;
if(!flags.exists(name))
+2
View File
@@ -163,6 +163,8 @@ class Main extends Sprite
}
public static function refreshAssets() @:privateAccess {
WindowUtils.resetTitle();
var game = FlxG.game; var daSndTray = Type.createInstance(game._customSoundTray = funkin.menus.ui.FunkinSoundTray, []);
var index:Int = game.numChildren - 1;
@@ -91,7 +91,7 @@ class SystemInfo extends FramerateCategory {
#end
if(openfl.display3D.Context3D.__glMemoryTotalAvailable != -1) {
var vRAMBytes:UInt = cast(flixel.FlxG.stage.context3D.gl.getParameter(openfl.display3D.Context3D.__glMemoryTotalAvailable), UInt);
var vRAMBytes:UInt = cast flixel.FlxG.stage.context3D.gl.getParameter(openfl.display3D.Context3D.__glMemoryTotalAvailable);
if (vRAMBytes == 1000 || vRAMBytes == 1 || vRAMBytes <= 0)
Logs.trace('Unable to grab GPU VRAM', ERROR, RED);
else
@@ -52,6 +52,10 @@ class FlagMacro {
parser = macro value.split(",").map((e) -> e.trim());
case macro: Array<String>:
parser = macro value.split(",");
case macro: Array<Int>:
parser = macro value.split(",").map((e) -> Std.parseInt(e));
case macro: Array<Float>:
parser = macro value.split(",").map((e) -> Std.parseFloat(e));
case macro: Array<Bool>:
parser = macro value.split(",").map((e) -> {
e = e.trim();
@@ -59,6 +63,8 @@ class FlagMacro {
});
case macro: Int:
parser = macro Std.parseInt(value);
case macro: Float:
parser = macro Std.parseFloat(value);
case macro: String:
parser = macro value;
case macro: Bool:
@@ -145,7 +151,7 @@ class FlagMacro {
case TPath({name: "Map", pack: []}):
Context.error("Flag " + field.name + " cannot be a Map<K, V>", field.pos);
default:
Context.error("Flag " + field.name + " must be either a Bool, Int, String, Array<String>, Array<Bool> or Array<TrimmedString>", field.pos);
Context.error("Flag " + field.name + " must be either a Bool, Int, Float, String, Array<String>, Array<Int>, Array<Float>, Array<Bool> or Array<TrimmedString>", field.pos);
}
if(parser == null) {
@@ -62,6 +62,7 @@ class AudioSwitchFix {
}
}
@:dox(hide)
typedef PlayingSound = {
var sound:FlxSound;
var time:Float;
@@ -20,10 +20,10 @@ class CrashHandler {
public static function onUncaughtError(e:UncaughtErrorEvent) {
var m:String = e.error;
if (Std.isOfType(e.error, Error)) {
var err = cast(e.error, Error);
var err:Error = cast e.error;
m = '${err.message}';
} else if (Std.isOfType(e.error, ErrorEvent)) {
var err = cast(e.error, ErrorEvent);
var err:ErrorEvent = cast e.error;
m = '${err.text}';
}
var stack = CallStack.exceptionStack();
+1 -1
View File
@@ -596,7 +596,7 @@ class CoolUtil
var fmt = new FlxTextFormat();
fmt.format.color = Reflect.hasField(fmtt, "color") ? FlxColor.fromString(fmtt.color) : text.color;
fmt.format.font = Reflect.hasField(fmtt, "font") ? Paths.font(fmtt.font) : text.font;
fmt.format.font = Reflect.hasField(fmtt, "font") ? Paths.getFontName(Paths.font(fmtt.font)) : text.font;
fmt.format.size = Reflect.hasField(fmtt, "size") ? Std.parseInt(fmtt.size) : text.size;
fmt.format.italic = Reflect.hasField(fmtt, "italic") ? fmtt.italic == "true" : text.italic;
fmt.format.bold = Reflect.hasField(fmtt, "bold") ? fmtt.bold == "true" : text.bold;
-21
View File
@@ -151,25 +151,4 @@ class MemoryUtil {
#end
return "Unknown";
}
private static var _nb:Int = 0;
private static var _nbD:Int = 0;
private static var _zombie:Dynamic;
public static function destroyFlixelZombies() {
#if cpp
// Gc.enterGCFreeZone();
while ((_zombie = Gc.getNextZombie()) != null) {
_nb++;
if (_zombie is flixel.util.FlxDestroyUtil.IFlxDestroyable) {
flixel.util.FlxDestroyUtil.destroy(cast(_zombie, flixel.util.FlxDestroyUtil.IFlxDestroyable));
_nbD++;
}
}
Sys.println('Zombies: ${_nb}; IFlxDestroyable Zombies: ${_nbD}');
// Gc.exitGCFreeZone();
#end
}
}
+2 -2
View File
@@ -113,8 +113,8 @@ class NativeAPI {
if(backgroundColor == NONE)
backgroundColor = BLACK;
var fg = cast(foregroundColor, Int);
var bg = cast(backgroundColor, Int);
var fg:Int = cast foregroundColor;
var bg:Int = cast backgroundColor;
Windows.setConsoleColors((bg * 16) + fg);
#elseif sys
Sys.print("\x1b[0m");
+53 -1
View File
@@ -6,6 +6,13 @@ import funkin.backend.FunkinSprite.XMLAnimType;
import funkin.backend.FunkinSprite;
import funkin.game.Character;
import funkin.backend.system.ErrorCode;
import funkin.backend.FunkinSprite.XMLAnimType;
import flixel.util.FlxColor;
import haxe.xml.Access;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.ScriptPack;
import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.system.interfaces.IOffsetCompatible;
import haxe.xml.Access;
@@ -254,7 +261,7 @@ class XMLUtil {
cast(sprite, IOffsetCompatible).addOffset(animData.name, animData.x, animData.y);
if (sprite is FunkinSprite) {
var xmlSpr = cast(sprite, FunkinSprite);
var xmlSpr:FunkinSprite = cast sprite;
var name = animData.name;
switch(animData.animType) {
case BEAT:
@@ -330,6 +337,51 @@ class XMLUtil {
}
}
class XMLImportedScriptInfo {
public var path:String;
public var shortLived:Bool = false;
public var loadBefore:Bool = true;
public var importStageSprites:Bool = false; // maybe will change later?? - Nex
public var parentScriptPack:ScriptPack = null;
public function new(path:String, parentScriptPack:ScriptPack) {
this.parentScriptPack = parentScriptPack;
this.path = path;
}
public function getScript():Script
return parentScriptPack == null ? null : parentScriptPack.getByPath(path);
public static function prepareInfos(node:Access, parentScriptPack:ScriptPack, ?onScriptPreLoad:XMLImportedScriptInfo->Void):XMLImportedScriptInfo {
if (!node.has.script || parentScriptPack == null) return null;
var folder = node.getAtt("folder").getDefault("data/scripts/");
if (!folder.endsWith("/")) folder += "/";
var path = Paths.script(folder + node.getAtt("script"));
var daScript = Script.create(path);
if (daScript is DummyScript) {
Logs.trace('Script Extension at ${path} does not exist.', ERROR);
return null;
}
var infos = new XMLImportedScriptInfo(daScript.path, parentScriptPack);
infos.shortLived = node.getAtt("isShortLived") == "true" || node.getAtt("shortLived") == "true";
infos.importStageSprites = node.getAtt("importStageSprites") == "true";
@:privateAccess infos.loadBefore = shouldLoadBefore(node);
if (onScriptPreLoad != null) onScriptPreLoad(infos);
parentScriptPack.add(daScript);
daScript.set("scriptInfo", infos);
daScript.load();
return infos;
}
@:dox(hide) public static inline function shouldLoadBefore(node:Access):Bool
return node.getAtt("loadBefore") != "false";
}
typedef AnimData = {
var name:String;
var anim:String;
+28 -15
View File
@@ -675,7 +675,8 @@ class Charter extends UIState {
}
for (group in [notesGroup, eventsGroup]) {
cast(group, FlxTypedGroup<Dynamic>).forEach(function(s) {
var group:FlxTypedGroup<Dynamic> = cast group;
group.forEach(function(s) {
s.selected = false;
if (gridActionType == NONE) {
if (s is CharterNote) {
@@ -740,21 +741,27 @@ class Charter extends UIState {
selectionBox.bHeight = Std.int(Math.abs(mousePos.y - dragStartPos.y));
} else {
if (FlxG.keys.pressed.SHIFT) {
for (group in [notesGroup, eventsGroup])
for(n in cast(group, FlxTypedGroup<Dynamic>))
for (group in [notesGroup, eventsGroup]) {
var group:FlxTypedGroup<Dynamic> = cast group;
for(n in group)
if (n.handleSelection(selectionBox) && selection.contains(n))
selection.remove(n);
}
} else if (FlxG.keys.pressed.CONTROL) {
for (group in [notesGroup, eventsGroup])
for(n in cast(group, FlxTypedGroup<Dynamic>))
for (group in [notesGroup, eventsGroup]) {
var group:FlxTypedGroup<Dynamic> = cast group;
for(n in group)
if (n.handleSelection(selectionBox) && !selection.contains(n))
selection.push(n);
}
} else {
selection = [];
for (group in [notesGroup, eventsGroup])
for(n in cast(group, FlxTypedGroup<Dynamic>))
for (group in [notesGroup, eventsGroup]) {
var group:FlxTypedGroup<Dynamic> = cast group;
for(n in group)
if (n.handleSelection(selectionBox))
selection.push(n);
}
}
selection = __fixSelection(selection);
@@ -810,8 +817,14 @@ class Charter extends UIState {
changePoint.put();
}
if (s is CharterNote) cast(s, CharterNote).snappedToStrumline = true;
if (s is UISprite) cast(s, UISprite).cursor = BUTTON;
if (s is CharterNote) {
var s:CharterNote = cast s;
s.snappedToStrumline = true;
}
if (s is UISprite) {
var s:UISprite = cast s;
s.cursor = BUTTON;
}
}
if (!(verticalChange == 0 && horizontalChange == 0)) {
notesGroup.sortNotes(); eventsGroup.sortEvents();
@@ -1016,9 +1029,9 @@ class Charter extends UIState {
if (selection.length <= 0) return [];
notesGroup.autoSort = false;
for (objects in [notesGroup, eventsGroup]) {
var group = cast(objects, FlxTypedGroup<Dynamic>);
var member = 0;
for (group in [notesGroup, eventsGroup]) {
var group:FlxTypedGroup<Dynamic> = cast group;
var member:Int = 0;
while(member < group.members.length) {
var s = group.members[member];
if (selection.contains(s))
@@ -1375,7 +1388,7 @@ class Charter extends UIState {
var note:CharterNote = cast s;
CNote(note.step - minStep, note.id, note.strumLineID, note.susLength, note.type);
} else if (s is CharterEvent) {
var event = cast(s,CharterEvent);
var event:CharterEvent = cast s;
CEvent(event.step - minStep, [for (event in event.events) Reflect.copy(event)]);
}
];
@@ -1957,9 +1970,9 @@ typedef SelectionDragChange = {
public inline function loop(onNote:CharterNote->Void, ?onEvent:CharterEvent->Void, ?draggableOnly:Bool = true) {
for (s in this) {
if (s is CharterNote && onNote != null && (draggableOnly ? s.draggable: true))
onNote(cast(s, CharterNote));
onNote(cast s);
else if (s is CharterEvent && onEvent != null && (draggableOnly ? s.draggable: true))
onEvent(cast(s, CharterEvent));
onEvent(cast s);
}
}
}
@@ -63,7 +63,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
generateDefaultIcon(event.name);
case "Camera Movement":
// custom icon for camera movement
var state = cast(FlxG.state, Charter);
var state:Charter = cast FlxG.state;
if (event.params != null && event.params[0] != null && event.params[0] >= 0 && event.params[0] < state.strumLines.length) {
// camera movement, use health icon
var icon = Character.getIconFromCharName(state.strumLines.members[event.params[0]].strumLine.characters[0]);
@@ -33,7 +33,7 @@ class CharterNoteGroup extends FlxTypedGroup<CharterNote> {
noteFunc(__loopSprite);
}
for(c in Charter.selection.copy())
if (c != null && c is CharterNote) noteFunc(cast (c, CharterNote));
if (c != null && c is CharterNote) noteFunc(cast c);
__currentlyLooping = oldCur;
}
@@ -47,7 +47,7 @@ class CharterNoteHoverer extends CharterNote {
for (s in Charter.selection) {
if (s != null && s.draggable && s is CharterNote) {
var draggingNote:CharterNote = cast(s, CharterNote);
var draggingNote:CharterNote = cast s;
y = (draggingNote.step + verticalChange);
if (!FlxG.keys.pressed.SHIFT)
y -= ((draggingNote.step + verticalChange)
+4 -2
View File
@@ -55,8 +55,10 @@ class UIFileExplorer extends UISliceSprite {
if (uiElement != null) {
uiElement.alpha = alpha;
if (uiElement is UIButton)
cast(uiElement, UIButton).selectable = selectable;
if (uiElement is UIButton) {
var uiElement:UIButton = cast uiElement;
uiElement.selectable = selectable;
}
}
}
+6 -3
View File
@@ -21,9 +21,12 @@ class UITopMenu extends UISliceSprite {
public override function update(elapsed:Float) {
anyMenuOpened = false;
for(c in members) if (cast(c, UITopMenuButton).curMenu.contextMenuOpened()) {
anyMenuOpened = true;
break;
for(c in members) {
var c:UITopMenuButton = cast c;
if (c.curMenu.contextMenuOpened()) {
anyMenuOpened = true;
break;
}
}
super.update(elapsed);
+1 -1
View File
@@ -5,7 +5,7 @@ import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
class UIUtil {
public static function follow(spr:FlxSprite, target:FlxSprite, x:Float = 0, y:Float = 0) {
spr.cameras = target is UISprite ? cast(target, UISprite).__lastDrawCameras : target.cameras;
spr.cameras = target is UISprite ? ({var _:UISprite = cast target;_;}).__lastDrawCameras : target.cameras;
spr.setPosition(target.x + x, target.y + y);
spr.scrollFactor.set(target.scrollFactor.x, target.scrollFactor.y);
}
+69 -17
View File
@@ -8,6 +8,9 @@ import flixel.util.FlxColor;
import funkin.backend.FunkinSprite;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.ScriptPack;
import funkin.backend.scripting.events.CharacterNodeEvent;
import funkin.backend.scripting.events.CharacterXMLEvent;
import funkin.backend.scripting.events.DanceEvent;
import funkin.backend.scripting.events.CancellableEvent;
import funkin.backend.scripting.events.DirectionAnimEvent;
@@ -46,8 +49,13 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public var cameraOffset:FlxPoint = FlxPoint.get(0, 0);
public var globalOffset:FlxPoint = FlxPoint.get(0, 0);
public var script:Script;
public var xml:Access;
public var scripts:ScriptPack;
public var xmlImportedScripts:Array<XMLImportedScriptInfo> = [];
public var script(default, set):Script;
public function prepareInfos(node:Access)
return XMLImportedScriptInfo.prepareInfos(node, scripts, (infos) -> xmlImportedScripts.push(infos));
public var idleSuffix:String = "";
public var stunned(default, set):Bool = false;
@@ -74,16 +82,15 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
script = Script.create(Paths.script(Path.withoutExtension(Paths.xml('characters/$curCharacter')), null, true));
else
script = new DummyScript(curCharacter);
script.setParent(this);
script.load();
buildCharacter(xml);
script.call("create");
scripts.call("create");
if (script == null)
script = new DummyScript(curCharacter);
script.call("postCreate");
scripts.call("postCreate");
}
@:noCompletion var __swappedLeftRightAnims:Bool = false;
@@ -120,7 +127,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
override function update(elapsed:Float) {
super.update(elapsed);
script.call("update", [elapsed]);
scripts.call("update", [elapsed]);
if (stunned) {
__stunnedTime += elapsed;
if (__stunnedTime > Constants.STUNNED_TIME)
@@ -139,7 +146,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
if(debugMode) return;
var event = EventManager.get(DanceEvent).recycle(danced);
script.call("onDance", [event]);
scripts.call("onDance", [event]);
if (event.cancelled) return;
if (isDanceLeftDanceRight)
@@ -174,7 +181,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
*/
public var danceOnBeat:Bool = true;
public override function beatHit(curBeat:Int) {
script.call("beatHit", [curBeat]);
scripts.call("beatHit", [curBeat]);
if (danceOnBeat && (curBeat + beatOffset) % beatInterval == 0 && !__lockAnimThisFrame)
tryDance();
@@ -184,7 +191,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
script.call("measureHit", [curMeasure]);
public override function stepHit(curStep:Int)
script.call("stepHit", [curStep]);
scripts.call("stepHit", [curStep]);
@:noCompletion var __reverseDrawProcedure:Bool = false;
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect {
@@ -254,7 +261,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public override function playAnim(AnimName:String, ?Force:Bool, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
var event = EventManager.get(PlayAnimEvent).recycle(AnimName, Force, Reversed, Frame, Context);
script.call("onPlayAnim", [event]);
scripts.call("onPlayAnim", [event]);
if (event.cancelled) return;
super.playAnim(event.animName, event.force, event.context, event.reverse, event.startingFrame);
@@ -269,16 +276,16 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
var event = EventManager.get(PointEvent).recycle(
midpoint.x + (isPlayer ? -100 : 150) + globalOffset.x + cameraOffset.x,
midpoint.y - 100 + globalOffset.y + cameraOffset.y);
script.call("onGetCamPos", [event]);
scripts.call("onGetCamPos", [event]);
midpoint.put();
return new FlxPoint(event.x, event.y);
}
public override function destroy() {
if(script != null) {
script.call('destroy');
script.destroy();
if(scripts != null) {
scripts.call('destroy');
scripts.destroy();
}
super.destroy();
@@ -321,9 +328,18 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
}
public inline function buildCharacter(xml:Access) {
this.xml = xml; // Modders wassup :D
for(node in xml.elements)
switch(node.name) {
case "use-extension" | "extension" | "ext":
if (!XMLImportedScriptInfo.shouldLoadBefore(node)) continue;
prepareInfos(node);
}
xml = scripts.event("onCharacterXMLParsed", EventManager.get(CharacterXMLEvent).recycle(this, xml)).xml;
sprite = curCharacter;
spriteAnimType = BEAT;
this.xml = xml; // Modders wassup :D
if (xml.x.exists("isPlayer")) playerOffsets = (xml.x.get("isPlayer") == "true");
if (xml.x.exists("x")) globalOffset.x = Std.parseFloat(xml.x.get("x"));
@@ -347,9 +363,19 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
if (hasInterval) beatInterval = Std.parseInt(xml.x.get("interval"));
loadSprite(Paths.image('characters/$sprite'));
for(node in xml.elements) {
switch(node.name) {
case "anim":
XMLUtil.addXMLAnimation(this, node);
case "use-extension" | "extension" | "ext":
if (XMLImportedScriptInfo.shouldLoadBefore(node)) continue;
prepareInfos(node);
default:
// nothing
}
for (anim in xml.nodes.anim)
XMLUtil.addXMLAnimation(this, anim);
scripts.event("onCharacterNodeParsed", EventManager.get(CharacterNodeEvent).recycle(this, node, node.name));
}
for (attribute in xml.x.attributes())
if (!characterProperties.contains(attribute))
@@ -357,6 +383,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
fixChar(__switchAnims, !hasInterval);
dance();
for (info in xmlImportedScripts) if (info.shortLived) {
var script = info.getScript();
if (script == null) continue;
scripts.remove(script);
script.destroy();
}
}
public static var characterProperties:Array<String> = [
@@ -440,6 +474,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
return stunned = b;
}
// ---- Backwards compat ----
// Interval at which the character will dance (higher number = slower dance)
@:noCompletion public var danceInterval(get, set):Int;
@:noCompletion private function set_danceInterval(v:Int)
@@ -451,10 +486,27 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public static var FALLBACK_CHARACTER:String = Constants.DEFAULT_CHARACTER;
public static var FALLBACK_DEAD_CHARACTER:String = Constants.DEFAULT_GAMEOVER_CHARACTER;
private function set_script(script:Script):Script {
if (scripts == null) (scripts = new ScriptPack("Character")).setParent(this);
var lastIndex = scripts.scripts.indexOf(this.script);
if(lastIndex >= 0) {
if(script == null) // last != null && new == null
scripts.scripts.splice(lastIndex, 1);
else // last != null && new != null
scripts.scripts[lastIndex] = script;
} else if(script != null) // last == null
scripts.insert(0, script);
return this.script = script;
}
// ---- end of Backwards compat ----
public static function getXMLFromCharName(character:OneOfTwo<String, Character>):Access {
var char:Character = null;
if (character is Character) {
char = cast(character, Character);
char = cast character;
character = char.curCharacter;
}
+1 -1
View File
@@ -208,7 +208,7 @@ class Note extends FlxSprite
public var strumRelativePos:Bool = true;
override function drawComplex(camera:FlxCamera) {
var downscrollCam = (camera is HudCamera ? cast(camera, HudCamera).downscroll : false);
var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false);
flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
if (downscrollCam) {
frameOffset.y += __notePosFrameOffset.y * 2;
+23 -8
View File
@@ -160,6 +160,11 @@ class PlayState extends MusicBeatState
* Boyfriend character
*/
public var boyfriend(get, set):Character;
/**
* Boyfriend character
* Same as boyfriend, just shorter
**/
public var bf(get, set):Character;
/**
* Strum line position
@@ -890,12 +895,12 @@ class PlayState extends MusicBeatState
Conductor.songPosition = 0;
Conductor.songPosition -= Conductor.crochet * introLength - Conductor.songOffset;
var swagCounter:Int = 0;
startTimer = new FlxTimer().start(Conductor.crochet / 1000, function(tmr:FlxTimer)
{
countdown(swagCounter++);
}, introLength);
if(introLength > 0) {
var swagCounter:Int = 0;
startTimer = new FlxTimer().start(Conductor.crochet / 1000, (tmr:FlxTimer) -> {
countdown(swagCounter++);
}, introLength);
}
gameAndCharsCall("onPostStartCountdown");
}
@@ -1073,7 +1078,7 @@ class PlayState extends MusicBeatState
vocals.pause();
}
if (!startTimer.finished)
if (startTimer != null && !startTimer.finished)
startTimer.active = false;
}
@@ -1093,7 +1098,7 @@ class PlayState extends MusicBeatState
resyncVocals();
}
if (!startTimer.finished)
if (startTimer != null && !startTimer.finished)
startTimer.active = true;
paused = false;
@@ -1880,6 +1885,16 @@ class PlayState extends MusicBeatState
strumLines.members[1].characters = [bf];
return bf;
}
private function set_bf(bf:Character):Character {
if (strumLines != null && strumLines.members[1] != null)
strumLines.members[1].characters = [bf];
return bf;
}
private function get_bf():Character {
if (strumLines != null && strumLines.members[1] != null)
return strumLines.members[1].characters[0];
return null;
}
private function get_dad():Character {
if (strumLines != null && strumLines.members[0] != null)
return strumLines.members[0].characters[0];
+9 -47
View File
@@ -2,6 +2,9 @@ package funkin.game;
import flixel.FlxState;
import flixel.math.FlxPoint;
import haxe.xml.Access;
import funkin.backend.utils.XMLUtil.XMLImportedScriptInfo;
import funkin.backend.system.interfaces.IBeatReceiver;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.events.StageNodeEvent;
@@ -30,6 +33,9 @@ class Stage extends FlxBasic implements IBeatReceiver {
public function setStagesSprites(script:Script)
for (k=>e in stageSprites) script.set(k, e);
public function prepareInfos(node:Access)
return XMLImportedScriptInfo.prepareInfos(node, PlayState.instance.scripts, (infos) -> xmlImportedScripts.push(infos));
public function new(stage:String, ?state:FlxState) {
super();
@@ -136,7 +142,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
PlayState.instance.add(PlayState.instance.comboGroup);
PlayState.instance.comboGroup;
case "use-extension" | "extension" | "ext":
if (__shouldLoadBefore(node) || XMLImportedScriptInfo.prepareInfos(node, this) == null) continue;
if (XMLImportedScriptInfo.shouldLoadBefore(node) || prepareInfos(node) == null) continue;
null;
default: null;
}
@@ -201,13 +207,10 @@ class Stage extends FlxBasic implements IBeatReceiver {
@:dox(hide) private function __pushNcheckNode(array:Array<Access>, node:Access) {
array.push(node);
if ((node.name == "use-extension" || node.name == "extension" || node.name == "ext") && __shouldLoadBefore(node))
XMLImportedScriptInfo.prepareInfos(node, this);
if ((node.name == "use-extension" || node.name == "extension" || node.name == "ext") && XMLImportedScriptInfo.shouldLoadBefore(node))
prepareInfos(node);
}
@:dox(hide) private static inline function __shouldLoadBefore(node:Access):Bool
return node.getAtt("loadBefore") != "false";
public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo):StageCharPos {
var charPos = new StageCharPos();
charPos.visible = charPos.active = false;
@@ -317,45 +320,4 @@ typedef StageCharPosInfo = {
var y:Float;
var flip:Bool;
var scroll:Float;
}
class XMLImportedScriptInfo {
public var path:String;
public var shortLived:Bool = false;
public var loadBefore:Bool = true;
public var importStageSprites:Bool = false;
public function new(path:String)
this.path = path;
public function getScript():Script
return PlayState.instance == null ? null : PlayState.instance.scripts.getByPath(path);
public static function prepareInfos(node:Access, ?stage:Stage):XMLImportedScriptInfo {
if (!node.has.script || PlayState.instance == null) return null;
var folder = node.getAtt("folder").getDefault("data/scripts/");
if (!folder.endsWith("/")) folder += "/";
var path = Paths.script(folder + node.getAtt("script"));
var daScript = Script.create(path);
if (daScript is DummyScript) {
var msg = 'Script Extension at ${path} does not exist';
if (stage != null) msg += ' through stage "${stage.stageName}"';
Logs.trace(msg + ".", ERROR);
return null;
}
var infos = new XMLImportedScriptInfo(daScript.path);
infos.shortLived = node.getAtt("isShortLived") == "true";
infos.importStageSprites = node.getAtt("importStageSprites") == "true";
@:privateAccess infos.loadBefore = Stage.__shouldLoadBefore(node);
if (stage != null) stage.xmlImportedScripts.push(infos);
PlayState.instance.scripts.add(daScript);
daScript.set("scriptInfo", infos);
daScript.load();
return infos;
}
}
+5 -4
View File
@@ -252,7 +252,8 @@ class StrumLine extends FlxTypedGroup<Strum> {
__justReleased.push(s.__getJustReleased(this));
}
var event = PlayState.instance.gameAndCharsEvent("onInputUpdate", EventManager.get(InputSystemEvent).recycle(__pressed, __justPressed, __justReleased, this, id));
var event = EventManager.get(InputSystemEvent).recycle(__pressed, __justPressed, __justReleased, this, id);
if (PlayState.instance != null) PlayState.instance.gameAndCharsEvent("onInputUpdate", event);
if (event.cancelled) return;
__pressed = CoolUtil.getDefault(event.pressed, []);
@@ -321,8 +322,8 @@ class StrumLine extends FlxTypedGroup<Strum> {
babyArrow.scrollSpeed = data.scrollSpeed;
var event = EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.members.indexOf(this), i, animPrefix);
event.__doAnimation = !MusicBeatState.skipTransIn;
event = PlayState.instance.gameAndCharsEvent("onStrumCreation", event);
event.__doAnimation = !MusicBeatState.skipTransIn && (PlayState.instance != null ? PlayState.instance.introLength > 0 : true);
if (PlayState.instance != null) event = PlayState.instance.gameAndCharsEvent("onStrumCreation", event);
if (!event.cancelled) {
babyArrow.frames = Paths.getFrames(event.sprite);
@@ -353,7 +354,7 @@ class StrumLine extends FlxTypedGroup<Strum> {
insert(i, babyArrow);
PlayState.instance.gameAndCharsEvent("onPostStrumCreation", event);
if (PlayState.instance != null) PlayState.instance.gameAndCharsEvent("onPostStrumCreation", event);
return babyArrow;
}
+3
View File
@@ -2,6 +2,7 @@ package funkin.menus;
#if MOD_SUPPORT
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import funkin.backend.assets.ModsFolder;
import haxe.io.Path;
import sys.FileSystem;
@@ -28,6 +29,8 @@ class ModSwitchMenu extends MusicBeatSubstate {
alphabets = new FlxTypedGroup<Alphabet>();
for(mod in mods) {
var a = new Alphabet(0, 0, mod == null ? "DISABLE MODS" : mod, true);
if(mod == ModsFolder.currentModFolder)
a.color = FlxColor.LIME;
a.isMenuItem = true;
a.scrollFactor.set();
alphabets.add(a);
+1 -1
View File
@@ -355,7 +355,7 @@ class IntroText {
for(e in lines) {
if (e is String) {
var text = cast(e, String);
for(k=>e in state.curWacky) text = text.replace('{introText${k+1}', e);
for(k=>e in state.curWacky) text = text.replace('{introText${k+1}}', e);
state.addMoreText(text);
} else if (e is Dynamic) {
var image:TitleStateImage = e;
@@ -11,6 +11,7 @@ using StringTools;
class CreditsCodename extends funkin.options.OptionsScreen {
public var error:Bool = false;
public var totalContributions:Int = 0;
public var contribFormats:Array<FlxTextFormatMarkerPair> = [];
public override function new()
{
@@ -55,12 +56,17 @@ class CreditsCodename extends funkin.options.OptionsScreen {
if(parent == null || parent.treeParent == null) return;
var text:String = parent.treeParent.pathDesc.text;
parent.treeParent.pathDesc.text = "";
parent.treeParent.pathDesc.applyMarkup(text, [
parent.treeParent.pathDesc.applyMarkup(text, contribFormats = [
new FlxTextFormatMarkerPair(new FlxTextFormat(Constants.MAIN_DEVS_COLOR), '*'),
new FlxTextFormatMarkerPair(new FlxTextFormat(FlxColor.interpolate(Constants.MIN_CONTRIBUTIONS_COLOR, Constants.MAIN_DEVS_COLOR, Options.contributors[curSelected].contributions / totalContributions)), '~')
]);
}
override function close() {
super.close();
for (frmt in contribFormats) parent.treeParent.pathDesc.removeFormat(frmt.format);
}
public function checkUpdate():Bool {
var curTime:Float = Date.now().getTime();
if(Options.lastUpdated != null && curTime < Options.lastUpdated + 120000) return false; // Fuck you Github rate limits - Nex
+1 -1
View File
@@ -41,7 +41,7 @@ class Alphabet extends FlxSpriteGroup
private override function set_color(c:Int):Int {
for(e in group.members) {
if (e is AlphaCharacter) {
var char = cast(e, AlphaCharacter);
var char:AlphaCharacter = cast e;
char.setColor(c, isBold);
}
}