FUCK SPACES!!!! TABS RULES!!! 💪💪💪💪

This commit is contained in:
Yoshman29
2023-03-25 22:53:47 +01:00
parent c259385f2a
commit a63e5f5958
135 changed files with 6799 additions and 6799 deletions
+105 -105
View File
@@ -17,137 +17,137 @@ using StringTools;
class AtlasFrameMaker extends FlxFramesCollection{ class AtlasFrameMaker extends FlxFramesCollection{
//public static var widthoffset:Int = 0; //public static var widthoffset:Int = 0;
//public static var heightoffset:Int = 0; //public static var heightoffset:Int = 0;
//public static var excludeArray:Array<String>; //public static var excludeArray:Array<String>;
/** /**
* Creates Frames from TextureAtlas(very early and broken ok) Originally made for FNF HD by Smokey and Rozebud * Creates Frames from TextureAtlas(very early and broken ok) Originally made for FNF HD by Smokey and Rozebud
* *
* @param key The file path. * @param key The file path.
* @param _excludeArray Use this to only create selected animations. Keep null to create all of them. * @param _excludeArray Use this to only create selected animations. Keep null to create all of them.
* *
*/ */
public static function construct(key:String,?_excludeArray:Array<String> = null):FlxFramesCollection{ public static function construct(key:String,?_excludeArray:Array<String> = null):FlxFramesCollection{
// widthoffset = _widthoffset; // widthoffset = _widthoffset;
// heightoffset = _heightoffset; // heightoffset = _heightoffset;
var frameCollection:FlxFramesCollection; var frameCollection:FlxFramesCollection;
var frameArray:Array<Array<FlxFrame>> = []; var frameArray:Array<Array<FlxFrame>> = [];
var animationData:AnimationData = Json.parse(Assets.getText(key + "/Animation.json")); var animationData:AnimationData = Json.parse(Assets.getText(key + "/Animation.json"));
var atlasData:AtlasData = Json.parse(Assets.getText(key + "/spritemap.json").replace("\uFEFF", ""));//FIXED UTF8 w/ BOM error var atlasData:AtlasData = Json.parse(Assets.getText(key + "/spritemap.json").replace("\uFEFF", ""));//FIXED UTF8 w/ BOM error
var bitmapData:BitmapData = Assets.getBitmapData(key + "/spritemap.png"); var bitmapData:BitmapData = Assets.getBitmapData(key + "/spritemap.png");
var ss = new SpriteAnimationLibrary(animationData, atlasData, bitmapData); var ss = new SpriteAnimationLibrary(animationData, atlasData, bitmapData);
var t = ss.createAnimation(); var t = ss.createAnimation();
if(_excludeArray == null){ if(_excludeArray == null){
_excludeArray = t.getFrameLabels(); _excludeArray = t.getFrameLabels();
} }
frameCollection = new FlxFramesCollection(FlxGraphic.fromBitmapData(bitmapData),FlxFrameCollectionType.IMAGE); frameCollection = new FlxFramesCollection(FlxGraphic.fromBitmapData(bitmapData),FlxFrameCollectionType.IMAGE);
for(x in t.getFrameLabels()){ for(x in t.getFrameLabels()){
frameArray.push(getFramesArray(t, x,_excludeArray)); frameArray.push(getFramesArray(t, x,_excludeArray));
} }
for(x in frameArray){ for(x in frameArray){
for(y in x){ for(y in x){
frameCollection.pushFrame(y); frameCollection.pushFrame(y);
} }
} }
return frameCollection; return frameCollection;
} }
@:noCompletion static function getFramesArray(t:SpriteMovieClip,animation:String,_excludeArray:Array<String>):Array<FlxFrame> @:noCompletion static function getFramesArray(t:SpriteMovieClip,animation:String,_excludeArray:Array<String>):Array<FlxFrame>
{ {
var sizeInfo:Rectangle = new Rectangle(0,0); var sizeInfo:Rectangle = new Rectangle(0,0);
t.currentLabel = animation; t.currentLabel = animation;
var bitMapArray:Array<BitmapData> = []; var bitMapArray:Array<BitmapData> = [];
var daFramez:Array<FlxFrame> = []; var daFramez:Array<FlxFrame> = [];
var firstPass = true; var firstPass = true;
var frameSize:FlxPoint = new FlxPoint(0,0); var frameSize:FlxPoint = new FlxPoint(0,0);
for (i in t.getFrame(animation)...t.numFrames){ for (i in t.getFrame(animation)...t.numFrames){
t.currentFrame = i; t.currentFrame = i;
if (t.currentLabel == animation){ if (t.currentLabel == animation){
if (_excludeArray.contains(animation)){ if (_excludeArray.contains(animation)){
sizeInfo = t.getBounds(t); sizeInfo = t.getBounds(t);
var bitmapShit:BitmapData = new BitmapData( var bitmapShit:BitmapData = new BitmapData(
Std.int(sizeInfo.width + Math.abs(sizeInfo.x)),Std.int(sizeInfo.height +Math.abs(sizeInfo.y)),true,0); Std.int(sizeInfo.width + Math.abs(sizeInfo.x)),Std.int(sizeInfo.height +Math.abs(sizeInfo.y)),true,0);
bitmapShit.draw(t,null,null,null,null,true); bitmapShit.draw(t,null,null,null,null,true);
bitMapArray.push(bitmapShit); bitMapArray.push(bitmapShit);
if (firstPass){ if (firstPass){
frameSize.set(bitmapShit.width,bitmapShit.height); frameSize.set(bitmapShit.width,bitmapShit.height);
firstPass = false; firstPass = false;
} }
} }
} }
else break; else break;
} }
for (i in 0...bitMapArray.length){ for (i in 0...bitMapArray.length){
var b = FlxGraphic.fromBitmapData(bitMapArray[i]); var b = FlxGraphic.fromBitmapData(bitMapArray[i]);
var theFrame = new FlxFrame(b); var theFrame = new FlxFrame(b);
theFrame.parent = b; theFrame.parent = b;
theFrame.name = animation + i; theFrame.name = animation + i;
theFrame.sourceSize.set(frameSize.x,frameSize.y); theFrame.sourceSize.set(frameSize.x,frameSize.y);
theFrame.frame = new FlxRect(0, 0, bitMapArray[i].width, bitMapArray[i].height); theFrame.frame = new FlxRect(0, 0, bitMapArray[i].width, bitMapArray[i].height);
daFramez.push(theFrame); daFramez.push(theFrame);
//trace(daFramez); //trace(daFramez);
} }
if (frameSize != null) if (frameSize != null)
frameSize.put(); frameSize.put();
return daFramez; return daFramez;
} }
/*public static function renderTest(key:String, animation:String, ?frame:Int = 0):Void /*public static function renderTest(key:String, animation:String, ?frame:Int = 0):Void
{ {
var animationData:AnimationData = Json.parse(Assets.getText(key + "/Animation.json")); var animationData:AnimationData = Json.parse(Assets.getText(key + "/Animation.json"));
var atlasData:AtlasData = Json.parse(Assets.getText(key + "/spritemap.json")); var atlasData:AtlasData = Json.parse(Assets.getText(key + "/spritemap.json"));
var bitmapData:BitmapData = Assets.getBitmapData(key + "/spritemap.png"); var bitmapData:BitmapData = Assets.getBitmapData(key + "/spritemap.png");
var ss = new SpriteAnimationLibrary(animationData, atlasData, bitmapData); var ss = new SpriteAnimationLibrary(animationData, atlasData, bitmapData);
var t = ss.createAnimation(); var t = ss.createAnimation();
var bitMapArray:Array<BitmapData> = []; var bitMapArray:Array<BitmapData> = [];
for (i in 0...t.numFrames){ for (i in 0...t.numFrames){
t.currentFrame = i; t.currentFrame = i;
if (t.currentLabel == animation){ if (t.currentLabel == animation){
//trace(t.currentFrame); //trace(t.currentFrame);
var bitmapShit:BitmapData = new BitmapData(Std.int(t.width),Std.int(t.height),true,0); var bitmapShit:BitmapData = new BitmapData(Std.int(t.width),Std.int(t.height),true,0);
//bitmapShit.drawWithQuality(t,null,null,null,null,true); //bitmapShit.drawWithQuality(t,null,null,null,null,true);
bitmapShit.draw(t, new Matrix(1, 0, 0, 1, t.width/2, t.height/2), null, null, null, false); bitmapShit.draw(t, new Matrix(1, 0, 0, 1, t.width/2, t.height/2), null, null, null, false);
bitMapArray.push(bitmapShit); bitMapArray.push(bitmapShit);
} }
} }
saveImage(bitMapArray[frame]); saveImage(bitMapArray[frame]);
} }
public static function saveImage(bitmapData:BitmapData) public static function saveImage(bitmapData:BitmapData)
{ {
var b:ByteArray = new ByteArray(); var b:ByteArray = new ByteArray();
b = bitmapData.encode(bitmapData.rect, new PNGEncoderOptions(true), b); b = bitmapData.encode(bitmapData.rect, new PNGEncoderOptions(true), b);
new FileDialog().save(b, "png", null, "file"); new FileDialog().save(b, "png", null, "file");
} }
*/ */
} }
+112 -112
View File
@@ -29,146 +29,146 @@ import flixel.FlxCamera;
import away3d.containers.View3D; import away3d.containers.View3D;
class Flx3DCamera extends FlxCamera { class Flx3DCamera extends FlxCamera {
private static var __3DIDS:Int = 0; private static var __3DIDS:Int = 0;
public var view:View3D; public var view:View3D;
var meshes:Array<Mesh> = []; var meshes:Array<Mesh> = [];
public function new(X:Int = 0, Y:Int = 0, Width:Int = 0, Height:Int = 0, DefaultZoom:Float = 1) { public function new(X:Int = 0, Y:Int = 0, Width:Int = 0, Height:Int = 0, DefaultZoom:Float = 1) {
if (!Flx3DUtil.is3DAvailable()) if (!Flx3DUtil.is3DAvailable())
throw "[Flx3DCamera] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getTotal3D() + ", Max stages allowed: " + FlxG.stage.stage3Ds.length + "."; throw "[Flx3DCamera] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getTotal3D() + ", Max stages allowed: " + FlxG.stage.stage3Ds.length + ".";
super(X, Y, Width, Height, DefaultZoom); super(X, Y, Width, Height, DefaultZoom);
__cur3DStageID = __3DIDS++; __cur3DStageID = __3DIDS++;
view = new View3D(); view = new View3D();
view.width = this.width; view.width = this.width;
view.height = this.height; view.height = this.height;
view.visible = true; view.visible = true;
FlxG.stage.addChild(view); FlxG.stage.addChild(view);
} }
public override function render() { public override function render() {
super.render(); super.render();
view.x = FlxG.game.x + FlxG.game.scaleX * (flashSprite.x + flashSprite.scaleX * (_scrollRect.x + _scrollRect.scaleX * (_scrollRect.scrollRect.x))); view.x = FlxG.game.x + FlxG.game.scaleX * (flashSprite.x + flashSprite.scaleX * (_scrollRect.x + _scrollRect.scaleX * (_scrollRect.scrollRect.x)));
view.x -= _scrollRect.scrollRect.width * ((zoom / initialZoom) - 1) / 2; view.x -= _scrollRect.scrollRect.width * ((zoom / initialZoom) - 1) / 2;
view.y = FlxG.game.y + FlxG.game.scaleY * (flashSprite.y + flashSprite.scaleY * (_scrollRect.y + _scrollRect.scaleY * (_scrollRect.scrollRect.y))); view.y = FlxG.game.y + FlxG.game.scaleY * (flashSprite.y + flashSprite.scaleY * (_scrollRect.y + _scrollRect.scaleY * (_scrollRect.scrollRect.y)));
view.y -= _scrollRect.scrollRect.height * ((zoom / initialZoom) - 1) / 2; view.y -= _scrollRect.scrollRect.height * ((zoom / initialZoom) - 1) / 2;
view.width = _scrollRect.scrollRect.width / initialZoom; view.width = _scrollRect.scrollRect.width / initialZoom;
view.width += _scrollRect.scrollRect.width / initialZoom * ((zoom / initialZoom) - 1); view.width += _scrollRect.scrollRect.width / initialZoom * ((zoom / initialZoom) - 1);
view.height = _scrollRect.scrollRect.height / initialZoom; view.height = _scrollRect.scrollRect.height / initialZoom;
view.height += _scrollRect.scrollRect.height / initialZoom * ((zoom / initialZoom) - 1); view.height += _scrollRect.scrollRect.height / initialZoom * ((zoom / initialZoom) - 1);
view.render(); view.render();
} }
public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) { public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) {
var model = Assets.getBytes(assetPath); var model = Assets.getBytes(assetPath);
if (model == null) if (model == null)
throw 'Model at ${assetPath} was not found.'; throw 'Model at ${assetPath} was not found.';
var context = new AssetLoaderContext(); var context = new AssetLoaderContext();
var noExt = Path.withoutExtension(assetPath); var noExt = Path.withoutExtension(assetPath);
trace(noExt); trace(noExt);
context.mapUrlToData('${Path.withoutDirectory(noExt)}.mtl', '$noExt.mtl'); context.mapUrlToData('${Path.withoutDirectory(noExt)}.mtl', '$noExt.mtl');
var material:TextureMaterial = null; var material:TextureMaterial = null;
if (texturePath != null) if (texturePath != null)
material = new TextureMaterial(Cast.bitmapTexture(texturePath), smoothTexture); material = new TextureMaterial(Cast.bitmapTexture(texturePath), smoothTexture);
return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) { return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) {
case "dae": new DAEParser(); case "dae": new DAEParser();
case "md2": new MD2Parser(); case "md2": new MD2Parser();
case "md5": new MD5MeshParser(); case "md5": new MD5MeshParser();
case "awd": new AWDParser(); case "awd": new AWDParser();
default: new OBJParser(); default: new OBJParser();
}, (event:Asset3DEvent) -> { }, (event:Asset3DEvent) -> {
if (event.asset != null && event.asset.assetType == Asset3DType.MESH) { if (event.asset != null && event.asset.assetType == Asset3DType.MESH) {
var mesh:Mesh = cast(event.asset, Mesh); var mesh:Mesh = cast(event.asset, Mesh);
if (material != null) if (material != null)
mesh.material = material; mesh.material = material;
meshes.push(mesh); meshes.push(mesh);
} }
callback(event); callback(event);
}); });
} }
private var __cur3DStageID:Int; private var __cur3DStageID:Int;
private var _loaders:Map<Asset3DLibraryBundle, AssetLoaderToken> = []; private var _loaders:Map<Asset3DLibraryBundle, AssetLoaderToken> = [];
private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken { private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken {
var token:AssetLoaderToken; var token:AssetLoaderToken;
var lib:Asset3DLibraryBundle; var lib:Asset3DLibraryBundle;
lib = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); lib = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
token = lib.loadData(data, context, null, parser); token = lib.loadData(data, context, null, parser);
token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> { token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> {
// ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232 // ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232
if (event.type == Asset3DEvent.ASSET_COMPLETE) { if (event.type == Asset3DEvent.ASSET_COMPLETE) {
var obj:ObjectContainer3D = null; var obj:ObjectContainer3D = null;
switch (event.asset.assetType) { switch (event.asset.assetType) {
case Asset3DType.LIGHT: case Asset3DType.LIGHT:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, LightBase) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, LightBase) ? cast event.asset : null;
case Asset3DType.CONTAINER: case Asset3DType.CONTAINER:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, ObjectContainer3D) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, ObjectContainer3D) ? cast event.asset : null;
case Asset3DType.MESH: case Asset3DType.MESH:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Mesh) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Mesh) ? cast event.asset : null;
case Asset3DType.SKYBOX: case Asset3DType.SKYBOX:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SkyBox) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SkyBox) ? cast event.asset : null;
case Asset3DType.TEXTURE_PROJECTOR: case Asset3DType.TEXTURE_PROJECTOR:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, TextureProjector) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, TextureProjector) ? cast event.asset : null;
case Asset3DType.CAMERA: case Asset3DType.CAMERA:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Camera3D) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Camera3D) ? cast event.asset : null;
case Asset3DType.SEGMENT_SET: case Asset3DType.SEGMENT_SET:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SegmentSet) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SegmentSet) ? cast event.asset : null;
} }
if (obj != null && obj.parent == null) if (obj != null && obj.parent == null)
view.scene.addChild(obj); view.scene.addChild(obj);
} }
if (onAssetCallback != null) if (onAssetCallback != null)
onAssetCallback(event); onAssetCallback(event);
}); });
token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> { token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> {
trace("Loader Finished..."); trace("Loader Finished...");
}); });
_loaders.set(lib,token); _loaders.set(lib,token);
return token; return token;
} }
override function destroy() { override function destroy() {
if (meshes != null) if (meshes != null)
for(mesh in meshes) for(mesh in meshes)
mesh.dispose(); mesh.dispose();
var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
bundle.stopAllLoadingSessions(); bundle.stopAllLoadingSessions();
@:privateAccess { @:privateAccess {
if (bundle._loadingSessions != null) { if (bundle._loadingSessions != null) {
for(load in bundle._loadingSessions) { for(load in bundle._loadingSessions) {
load.dispose(); load.dispose();
} }
} }
Asset3DLibrary._instances.remove('Flx3DView-${__cur3DStageID}'); Asset3DLibrary._instances.remove('Flx3DView-${__cur3DStageID}');
} }
FlxG.stage.removeChild(view); FlxG.stage.removeChild(view);
try { try {
view.dispose(); view.dispose();
} catch(e) { } catch(e) {
} }
super.destroy(); super.destroy();
} }
public inline function addChild(c) public inline function addChild(c)
view.scene.addChild(c); view.scene.addChild(c);
} }
+93 -93
View File
@@ -29,120 +29,120 @@ import funkin.windows.WindowsAPI.ConsoleColor;
// FlxView3D with helpers for easier updating // FlxView3D with helpers for easier updating
class Flx3DView extends FlxView3D { class Flx3DView extends FlxView3D {
private static var __3DIDS:Int = 0; private static var __3DIDS:Int = 0;
var meshes:Array<Mesh> = []; var meshes:Array<Mesh> = [];
public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) { public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) {
if (!Flx3DUtil.is3DAvailable()) if (!Flx3DUtil.is3DAvailable())
throw "[Flx3DView] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getTotal3D() + ", Max stages allowed: " + FlxG.stage.stage3Ds.length + "."; throw "[Flx3DView] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getTotal3D() + ", Max stages allowed: " + FlxG.stage.stage3Ds.length + ".";
super(x, y, width, height); super(x, y, width, height);
__cur3DStageID = __3DIDS++; __cur3DStageID = __3DIDS++;
} }
public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) { public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) {
var model = Assets.getBytes(assetPath); var model = Assets.getBytes(assetPath);
if (model == null) if (model == null)
throw 'Model at ${assetPath} was not found.'; throw 'Model at ${assetPath} was not found.';
var context = new AssetLoaderContext(); var context = new AssetLoaderContext();
var noExt = Path.withoutExtension(assetPath); var noExt = Path.withoutExtension(assetPath);
trace(noExt); trace(noExt);
context.mapUrlToData('${Path.withoutDirectory(noExt)}.mtl', '$noExt.mtl'); context.mapUrlToData('${Path.withoutDirectory(noExt)}.mtl', '$noExt.mtl');
var material:TextureMaterial = null; var material:TextureMaterial = null;
if (texturePath != null) if (texturePath != null)
material = new TextureMaterial(Cast.bitmapTexture(texturePath), smoothTexture); material = new TextureMaterial(Cast.bitmapTexture(texturePath), smoothTexture);
return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) { return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) {
case "dae": new DAEParser(); case "dae": new DAEParser();
case "md2": new MD2Parser(); case "md2": new MD2Parser();
case "md5": new MD5MeshParser(); case "md5": new MD5MeshParser();
case "awd": new AWDParser(); case "awd": new AWDParser();
default: new OBJParser(); default: new OBJParser();
}, (event:Asset3DEvent) -> { }, (event:Asset3DEvent) -> {
if (event.asset != null && event.asset.assetType == Asset3DType.MESH) { if (event.asset != null && event.asset.assetType == Asset3DType.MESH) {
var mesh:Mesh = cast(event.asset, Mesh); var mesh:Mesh = cast(event.asset, Mesh);
if (material != null) if (material != null)
mesh.material = material; mesh.material = material;
meshes.push(mesh); meshes.push(mesh);
} }
callback(event); callback(event);
}); });
} }
@:deprecated public function addMesh(assetPath:String, callback:Mesh->Void, ?texturePath:String, smoothTexture:Bool = true) { @:deprecated public function addMesh(assetPath:String, callback:Mesh->Void, ?texturePath:String, smoothTexture:Bool = true) {
Logs.trace('The addMesh() function is deprecated, use addModel instead!', ERROR, RED); Logs.trace('The addMesh() function is deprecated, use addModel instead!', ERROR, RED);
} }
private var __cur3DStageID:Int; private var __cur3DStageID:Int;
private var _loaders:Map<Asset3DLibraryBundle, AssetLoaderToken> = []; private var _loaders:Map<Asset3DLibraryBundle, AssetLoaderToken> = [];
private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken { private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken {
var token:AssetLoaderToken; var token:AssetLoaderToken;
var lib:Asset3DLibraryBundle; var lib:Asset3DLibraryBundle;
lib = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); lib = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
token = lib.loadData(data, context, null, parser); token = lib.loadData(data, context, null, parser);
token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> { token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> {
// ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232 // ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232
if (event.type == Asset3DEvent.ASSET_COMPLETE) { if (event.type == Asset3DEvent.ASSET_COMPLETE) {
var obj:ObjectContainer3D = null; var obj:ObjectContainer3D = null;
switch (event.asset.assetType) { switch (event.asset.assetType) {
case Asset3DType.LIGHT: case Asset3DType.LIGHT:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, LightBase) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, LightBase) ? cast event.asset : null;
case Asset3DType.CONTAINER: case Asset3DType.CONTAINER:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, ObjectContainer3D) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, ObjectContainer3D) ? cast event.asset : null;
case Asset3DType.MESH: case Asset3DType.MESH:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Mesh) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Mesh) ? cast event.asset : null;
case Asset3DType.SKYBOX: case Asset3DType.SKYBOX:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SkyBox) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SkyBox) ? cast event.asset : null;
case Asset3DType.TEXTURE_PROJECTOR: case Asset3DType.TEXTURE_PROJECTOR:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, TextureProjector) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, TextureProjector) ? cast event.asset : null;
case Asset3DType.CAMERA: case Asset3DType.CAMERA:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Camera3D) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, Camera3D) ? cast event.asset : null;
case Asset3DType.SEGMENT_SET: case Asset3DType.SEGMENT_SET:
obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SegmentSet) ? cast event.asset : null; obj = #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(event.asset, SegmentSet) ? cast event.asset : null;
} }
if (obj != null && obj.parent == null) if (obj != null && obj.parent == null)
view.scene.addChild(obj); view.scene.addChild(obj);
} }
if (onAssetCallback != null) if (onAssetCallback != null)
onAssetCallback(event); onAssetCallback(event);
}); });
token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> { token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> {
trace("Loader Finished..."); trace("Loader Finished...");
}); });
_loaders.set(lib,token); _loaders.set(lib,token);
return token; return token;
} }
override function destroy() { override function destroy() {
if (meshes != null) if (meshes != null)
for(mesh in meshes) for(mesh in meshes)
mesh.dispose(); mesh.dispose();
var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
bundle.stopAllLoadingSessions(); bundle.stopAllLoadingSessions();
@:privateAccess { @:privateAccess {
if (bundle._loadingSessions != null) { if (bundle._loadingSessions != null) {
for(load in bundle._loadingSessions) { for(load in bundle._loadingSessions) {
load.dispose(); load.dispose();
} }
} }
Asset3DLibrary._instances.remove('Flx3DView-${__cur3DStageID}'); Asset3DLibrary._instances.remove('Flx3DView-${__cur3DStageID}');
} }
super.destroy(); super.destroy();
} }
public inline function addChild(c) public inline function addChild(c)
view.scene.addChild(c); view.scene.addChild(c);
} }
+83 -83
View File
@@ -1,102 +1,102 @@
package funkin.chart; package funkin.chart;
class BaseGameParser { class BaseGameParser {
public static function parse(data:Dynamic, result:ChartData) { public static function parse(data:Dynamic, result:ChartData) {
// base fnf chart parsing // base fnf chart parsing
var data:SwagSong = data; var data:SwagSong = data;
if (Reflect.hasField(data, "song")) { if (Reflect.hasField(data, "song")) {
var field:Dynamic = Reflect.field(data, "song"); var field:Dynamic = Reflect.field(data, "song");
if (!(field is String)) if (!(field is String))
data = field; data = field;
} }
result.scrollSpeed = data.speed; result.scrollSpeed = data.speed;
result.stage = data.stage; result.stage = data.stage;
result.strumLines.push({ result.strumLines.push({
characters: [data.player2], characters: [data.player2],
type: 0, type: 0,
position: data.player2.startsWith("gf") ? "girlfriend" : "dad", position: data.player2.startsWith("gf") ? "girlfriend" : "dad",
notes: [] notes: []
}); });
result.strumLines.push({ result.strumLines.push({
characters: [data.player1], characters: [data.player1],
type: 1, type: 1,
position: "boyfriend", position: "boyfriend",
notes: [] notes: []
}); });
if (data.gf != "none") { if (data.gf != "none") {
result.strumLines.push({ result.strumLines.push({
characters: [data.gf != null ? data.gf : "gf"], characters: [data.gf != null ? data.gf : "gf"],
type: 2, type: 2,
position: "girlfriend", position: "girlfriend",
notes: [], notes: [],
visible: false, visible: false,
strumLinePos: 0.5 strumLinePos: 0.5
}); });
} }
result.meta.bpm = data.bpm; result.meta.bpm = data.bpm;
var camFocusedBF:Bool = false; var camFocusedBF:Bool = false;
var beatsPerMesure:Float = data.beatsPerMesure.getDefault(4); var beatsPerMesure:Float = data.beatsPerMesure.getDefault(4);
var curBPM:Float = data.bpm; var curBPM:Float = data.bpm;
var curTime:Float = 0; var curTime:Float = 0;
var curCrochet:Float = ((60 / curBPM) * 1000); var curCrochet:Float = ((60 / curBPM) * 1000);
if (data.notes != null) for(section in data.notes) { if (data.notes != null) for(section in data.notes) {
if (section == null) { if (section == null) {
curTime += curCrochet * beatsPerMesure; curTime += curCrochet * beatsPerMesure;
continue; // Yoshi Engine charts crash fix continue; // Yoshi Engine charts crash fix
} }
if (camFocusedBF != (camFocusedBF = section.mustHitSection)) { if (camFocusedBF != (camFocusedBF = section.mustHitSection)) {
result.events.push({ result.events.push({
time: curTime, time: curTime,
type: CAM_MOVEMENT, type: CAM_MOVEMENT,
params: [camFocusedBF ? 1 : 0] params: [camFocusedBF ? 1 : 0]
}); });
} }
if (section.sectionNotes != null) for(note in section.sectionNotes) { if (section.sectionNotes != null) for(note in section.sectionNotes) {
if (note[1] < 0) continue; if (note[1] < 0) continue;
var daStrumTime:Float = note[0]; var daStrumTime:Float = note[0];
var daNoteData:Int = Std.int(note[1] % 8); var daNoteData:Int = Std.int(note[1] % 8);
var daNoteType:Int = Std.int(note[1] / 8); var daNoteType:Int = Std.int(note[1] / 8);
var gottaHitNote:Bool = daNoteData >= 4 ? !section.mustHitSection : section.mustHitSection; var gottaHitNote:Bool = daNoteData >= 4 ? !section.mustHitSection : section.mustHitSection;
if (note.length > 2) { if (note.length > 2) {
if (note[3] is Int) if (note[3] is Int)
daNoteType = Chart.addNoteType(result, data.noteTypes[Std.int(note[3])-1]); daNoteType = Chart.addNoteType(result, data.noteTypes[Std.int(note[3])-1]);
else if (note[3] is String) else if (note[3] is String)
daNoteType = Chart.addNoteType(result, note[3]); daNoteType = Chart.addNoteType(result, note[3]);
} else { } else {
daNoteType = Chart.addNoteType(result, data.noteTypes[daNoteType-1]); daNoteType = Chart.addNoteType(result, data.noteTypes[daNoteType-1]);
} }
result.strumLines[gottaHitNote ? 1 : 0].notes.push({ result.strumLines[gottaHitNote ? 1 : 0].notes.push({
time: daStrumTime, time: daStrumTime,
id: daNoteData % 4, id: daNoteData % 4,
type: daNoteType, type: daNoteType,
sLen: note[2] sLen: note[2]
}); });
} }
if (section.changeBPM && section.bpm != curBPM) { if (section.changeBPM && section.bpm != curBPM) {
curCrochet = ((60 / (curBPM = section.bpm)) * 1000); curCrochet = ((60 / (curBPM = section.bpm)) * 1000);
result.events.push({ result.events.push({
time: curTime, time: curTime,
type: BPM_CHANGE, type: BPM_CHANGE,
params: [section.bpm] params: [section.bpm]
}); });
} }
curTime += curCrochet * beatsPerMesure; curTime += curCrochet * beatsPerMesure;
} }
} }
} }
typedef SwagSong = typedef SwagSong =
{ {
+144 -144
View File
@@ -13,42 +13,42 @@ import sys.FileSystem;
using StringTools; using StringTools;
class Chart { class Chart {
public static function loadChartMeta(songName:String, difficulty:String = "normal", fromMods:Bool = true) { public static function loadChartMeta(songName:String, difficulty:String = "normal", fromMods:Bool = true) {
var metaPath = Paths.file('songs/${songName.toLowerCase()}/meta.json'); var metaPath = Paths.file('songs/${songName.toLowerCase()}/meta.json');
var metaDiffPath = Paths.file('songs/${songName.toLowerCase()}/meta-${difficulty.toLowerCase()}.json'); var metaDiffPath = Paths.file('songs/${songName.toLowerCase()}/meta-${difficulty.toLowerCase()}.json');
var data:ChartMetaData = null; var data:ChartMetaData = null;
var fromMods:Bool = fromMods; var fromMods:Bool = fromMods;
for(path in [metaDiffPath, metaPath]) { for(path in [metaDiffPath, metaPath]) {
if (Assets.exists(path)) { if (Assets.exists(path)) {
fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS); fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS);
try { try {
data = Json.parse(Assets.getText(path)); data = Json.parse(Assets.getText(path));
} catch(e) { } catch(e) {
Logs.trace('Failed to load song metadata for ${songName} ($path): ${Std.string(e)}', ERROR); Logs.trace('Failed to load song metadata for ${songName} ($path): ${Std.string(e)}', ERROR);
} }
if (data != null) break; if (data != null) break;
} }
} }
if (data == null) if (data == null)
data = { data = {
name: songName, name: songName,
bpm: 100 bpm: 100
}; };
data.setFieldDefault("name", songName); data.setFieldDefault("name", songName);
data.setFieldDefault("beatsPerMesure", 4); data.setFieldDefault("beatsPerMesure", 4);
data.setFieldDefault("stepsPerBeat", 4); data.setFieldDefault("stepsPerBeat", 4);
data.setFieldDefault("needsVoices", true); data.setFieldDefault("needsVoices", true);
data.setFieldDefault("icon", "face"); data.setFieldDefault("icon", "face");
data.setFieldDefault("difficulties", []); data.setFieldDefault("difficulties", []);
data.setFieldDefault("coopAllowed", false); data.setFieldDefault("coopAllowed", false);
data.setFieldDefault("opponentModeAllowed", false); data.setFieldDefault("opponentModeAllowed", false);
data.setFieldDefault("displayName", data.name); data.setFieldDefault("displayName", data.name);
data.setFieldDefault("parsedColor", data.color.getColorFromDynamic()); data.setFieldDefault("parsedColor", data.color.getColorFromDynamic());
if (data.difficulties.length <= 0) { 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/${songName.toLowerCase()}/charts/', false, !fromMods)) if (Path.extension(f = f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
if (data.difficulties.length == 3) { if (data.difficulties.length == 3) {
var hasHard = false, hasNormal = false, hasEasy = false; var hasHard = false, hasNormal = false, hasEasy = false;
for(d in data.difficulties) { for(d in data.difficulties) {
@@ -64,133 +64,133 @@ class Chart {
data.difficulties[2] = "HARD"; data.difficulties[2] = "HARD";
} }
} }
} }
if (data.difficulties.length <= 0) if (data.difficulties.length <= 0)
data.difficulties.push("CHART MISSING"); data.difficulties.push("CHART MISSING");
return data; return data;
} }
public static function parse(songName:String, difficulty:String = "normal"):ChartData { public static function parse(songName:String, difficulty:String = "normal"):ChartData {
var chartPath = Paths.chart(songName, difficulty); var chartPath = Paths.chart(songName, difficulty);
var base:ChartData = { var base:ChartData = {
strumLines: [], strumLines: [],
noteTypes: [], noteTypes: [],
events: [], events: [],
meta: { meta: {
name: null name: null
}, },
scrollSpeed: 2, scrollSpeed: 2,
stage: "stage", stage: "stage",
codenameChart: true, codenameChart: true,
fromMods: Paths.assetsTree.existsSpecific(chartPath, "TEXT", MODS) fromMods: Paths.assetsTree.existsSpecific(chartPath, "TEXT", MODS)
}; };
if (!Assets.exists(chartPath)) { if (!Assets.exists(chartPath)) {
Logs.trace('Chart for song ${songName} ($difficulty) at "$chartPath" was not found.', ERROR, RED); Logs.trace('Chart for song ${songName} ($difficulty) at "$chartPath" was not found.', ERROR, RED);
return base; return base;
} }
var data:Dynamic = null; var data:Dynamic = null;
try { try {
data = Json.parse(Assets.getText(chartPath)); data = Json.parse(Assets.getText(chartPath));
} catch(e) { } catch(e) {
Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED); Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED);
} }
/** /**
* CHART CONVERSION * CHART CONVERSION
*/ */
#if REGION #if REGION
if (Reflect.hasField(data, "codenameChart") && Reflect.field(data, "codenameChart") == true) { if (Reflect.hasField(data, "codenameChart") && Reflect.field(data, "codenameChart") == true) {
// codename chart // codename chart
base = data; base = data;
} else { } else {
// base game chart // base game chart
BaseGameParser.parse(data, base); BaseGameParser.parse(data, base);
} }
#end #end
if (base.meta == null) if (base.meta == null)
base.meta = loadChartMeta(songName, difficulty, base.fromMods); base.meta = loadChartMeta(songName, difficulty, base.fromMods);
else { else {
var loadedMeta = loadChartMeta(songName, difficulty, base.fromMods); 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); var f = Reflect.field(base.meta, field);
if (f != null) if (f != null)
Reflect.setField(loadedMeta, field, f); Reflect.setField(loadedMeta, field, f);
} }
base.meta = loadedMeta; base.meta = loadedMeta;
} }
return base; return base;
} }
public static function addNoteType(chart:ChartData, noteTypeName:String):Int { public static function addNoteType(chart:ChartData, noteTypeName:String):Int {
switch(noteTypeName.trim()) { switch(noteTypeName.trim()) {
case "Default Note" | null | "": case "Default Note" | null | "":
return 0; return 0;
default: default:
var index = chart.noteTypes.indexOf(noteTypeName); var index = chart.noteTypes.indexOf(noteTypeName);
if (index > -1) if (index > -1)
return index+1; return index+1;
chart.noteTypes.push(noteTypeName); chart.noteTypes.push(noteTypeName);
return chart.noteTypes.length; return chart.noteTypes.length;
} }
} }
/** /**
* Saves the chart to the specific song folder path. * Saves the chart to the specific song folder path.
* @param songFolderPath Path to the song folder (ex: `mods/your mod/songs/song/`) * @param songFolderPath Path to the song folder (ex: `mods/your mod/songs/song/`)
* @param chart Chart to save * @param chart Chart to save
* @param difficulty Name of the difficulty * @param difficulty Name of the difficulty
* @param saveSettings * @param saveSettings
* @return Filtered chart used for saving. * @return Filtered chart used for saving.
*/ */
public static function save(songFolderPath:String, chart:ChartData, difficulty:String = "normal", ?saveSettings:ChartSaveSettings):ChartData { public static function save(songFolderPath:String, chart:ChartData, difficulty:String = "normal", ?saveSettings:ChartSaveSettings):ChartData {
if (saveSettings == null) saveSettings = {}; if (saveSettings == null) saveSettings = {};
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart); var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart);
var meta = filteredChart.meta; var meta = filteredChart.meta;
// idk how null reacts to it so better be sure // idk how null reacts to it so better be sure
#if sys #if sys
if (!FileSystem.exists('${songFolderPath}\\charts\\')) if (!FileSystem.exists('${songFolderPath}\\charts\\'))
FileSystem.createDirectory('${songFolderPath}\\charts\\'); FileSystem.createDirectory('${songFolderPath}\\charts\\');
var chartPath = '${songFolderPath}\\charts\\${difficulty.trim()}.json'; var chartPath = '${songFolderPath}\\charts\\${difficulty.trim()}.json';
var metaPath = '${songFolderPath}\\meta.json'; var metaPath = '${songFolderPath}\\meta.json';
File.saveContent(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? "\t" : null)); File.saveContent(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? "\t" : null));
if (saveSettings.overrideExistingMeta == true || !FileSystem.exists(metaPath)) if (saveSettings.overrideExistingMeta == true || !FileSystem.exists(metaPath))
File.saveContent(metaPath, Json.stringify(meta, null, saveSettings.prettyPrint == true ? "\t" : null)); File.saveContent(metaPath, Json.stringify(meta, null, saveSettings.prettyPrint == true ? "\t" : null));
#end #end
return filteredChart; return filteredChart;
} }
public static function filterChartForSaving(chart:ChartData, ?saveMetaInChart:Null<Bool>):ChartData { public static function filterChartForSaving(chart:ChartData, ?saveMetaInChart:Null<Bool>):ChartData {
var data = Reflect.copy(chart); // make a copy of the chart to leave the OG intact var data = Reflect.copy(chart); // make a copy of the chart to leave the OG intact
if (saveMetaInChart != true) { if (saveMetaInChart != true) {
data.meta = null; data.meta = null;
} else { } else {
data.meta = Reflect.copy(chart.meta); // also make a copy of the metadata to leave the OG intact. data.meta = Reflect.copy(chart.meta); // also make a copy of the metadata to leave the OG intact.
if (data.meta != null) data.meta.parsedColor = null; if (data.meta != null) data.meta.parsedColor = null;
} }
data.fromMods = null; data.fromMods = null;
var sortedData:Dynamic = {}; var sortedData:Dynamic = {};
for(f in Reflect.fields(data)) { for(f in Reflect.fields(data)) {
var v = Reflect.field(data, f); var v = Reflect.field(data, f);
if (v != null) if (v != null)
Reflect.setField(sortedData, f, v); Reflect.setField(sortedData, f, v);
} }
return sortedData; return sortedData;
} }
} }
typedef ChartSaveSettings = { typedef ChartSaveSettings = {
var ?overrideExistingMeta:Bool; var ?overrideExistingMeta:Bool;
var ?saveMetaInChart:Bool; var ?saveMetaInChart:Bool;
var ?prettyPrint:Bool; var ?prettyPrint:Bool;
} }
+72 -72
View File
@@ -3,102 +3,102 @@ package funkin.chart;
import flixel.util.FlxColor; import flixel.util.FlxColor;
typedef ChartData = { typedef ChartData = {
public var strumLines:Array<ChartStrumLine>; public var strumLines:Array<ChartStrumLine>;
public var events:Array<ChartEvent>; public var events:Array<ChartEvent>;
public var meta:ChartMetaData; public var meta:ChartMetaData;
public var codenameChart:Bool; public var codenameChart:Bool;
public var stage:String; public var stage:String;
public var scrollSpeed:Float; public var scrollSpeed:Float;
public var noteTypes:Array<String>; public var noteTypes:Array<String>;
public var ?fromMods:Bool; public var ?fromMods:Bool;
} }
typedef ChartMetaData = { typedef ChartMetaData = {
public var name:String; public var name:String;
public var ?bpm:Float; public var ?bpm:Float;
public var ?displayName:String; public var ?displayName:String;
public var ?beatsPerMesure:Float; public var ?beatsPerMesure:Float;
public var ?stepsPerBeat:Float; public var ?stepsPerBeat:Float;
public var ?needsVoices:Bool; public var ?needsVoices:Bool;
public var ?icon:String; public var ?icon:String;
public var ?color:Dynamic; public var ?color:Dynamic;
public var ?difficulties:Array<String>; public var ?difficulties:Array<String>;
public var ?coopAllowed:Bool; public var ?coopAllowed:Bool;
public var ?opponentModeAllowed:Bool; public var ?opponentModeAllowed:Bool;
// NOT TO BE EXPORTED // NOT TO BE EXPORTED
public var ?parsedColor:FlxColor; public var ?parsedColor:FlxColor;
} }
typedef ChartStrumLine = { typedef ChartStrumLine = {
var characters:Array<String>; var characters:Array<String>;
var type:ChartStrumLineType; var type:ChartStrumLineType;
var notes:Array<ChartNote>; var notes:Array<ChartNote>;
var position:String; var position:String;
var ?strumLinePos:Float; // 0.25 = default opponent pos, 0.75 = default boyfriend pos var ?strumLinePos:Float; // 0.25 = default opponent pos, 0.75 = default boyfriend pos
var ?visible:Null<Bool>; var ?visible:Null<Bool>;
} }
typedef ChartNote = { typedef ChartNote = {
var time:Float; // time at which the note will be hit (ms) var time:Float; // time at which the note will be hit (ms)
var id:Int; // strum id of the note var id:Int; // strum id of the note
var type:Int; // type (int) of the note var type:Int; // type (int) of the note
var sLen:Float; // sustain length of the note (ms) var sLen:Float; // sustain length of the note (ms)
} }
typedef ChartEvent = { typedef ChartEvent = {
var time:Float; var time:Float;
var type:ChartEventType; var type:ChartEventType;
var params:Array<Dynamic>; var params:Array<Dynamic>;
} }
@:enum @:enum
abstract ChartStrumLineType(Int) from Int to Int { abstract ChartStrumLineType(Int) from Int to Int {
/** /**
* STRUMLINE IS MARKED AS OPPONENT - WILL BE PLAYED BY CPU, OR PLAYED BY PLAYER IF OPPONENT MODE IS ON * STRUMLINE IS MARKED AS OPPONENT - WILL BE PLAYED BY CPU, OR PLAYED BY PLAYER IF OPPONENT MODE IS ON
*/ */
var OPPONENT = 0; var OPPONENT = 0;
/** /**
* STRUMLINE IS MARKED AS PLAYER - WILL BE PLAYED AS PLAYER, OR PLAYED AS CPU IF OPPONENT MODE IS ON * STRUMLINE IS MARKED AS PLAYER - WILL BE PLAYED AS PLAYER, OR PLAYED AS CPU IF OPPONENT MODE IS ON
*/ */
var PLAYER = 1; var PLAYER = 1;
/** /**
* STRUMLINE IS MARKED AS ADDITIONAL - WILL BE PLAYED AS CPU EVEN IF OPPONENT MODE IS ENABLED * STRUMLINE IS MARKED AS ADDITIONAL - WILL BE PLAYED AS CPU EVEN IF OPPONENT MODE IS ENABLED
*/ */
var ADDITIONAL = 2; var ADDITIONAL = 2;
} }
@:enum @:enum
abstract ChartEventType(Int) from Int to Int { abstract ChartEventType(Int) from Int to Int {
/** /**
* CUSTOM EVENT * CUSTOM EVENT
* Params: * Params:
* - Function Name (String) * - Function Name (String)
* - Function Parameters... * - Function Parameters...
*/ */
var CUSTOM = -1; var CUSTOM = -1;
/** /**
* NO EVENT, MADE FOR UNKNOWN EVENTS / EVENTS THAT CANNOT BE PARSED * NO EVENT, MADE FOR UNKNOWN EVENTS / EVENTS THAT CANNOT BE PARSED
*/ */
var NONE = 0; var NONE = 0;
/** /**
* CAMERA MOVEMENT EVENT * CAMERA MOVEMENT EVENT
* Params: * Params:
* - Target Strumline ID (Int) * - Target Strumline ID (Int)
*/ */
var CAM_MOVEMENT = 1; var CAM_MOVEMENT = 1;
/** /**
* BPM CHANGE EVENT * BPM CHANGE EVENT
* Params: * Params:
* - Target BPM (Float) * - Target BPM (Float)
*/ */
var BPM_CHANGE = 2; var BPM_CHANGE = 2;
/** /**
* ALT ANIM TOGGLE * ALT ANIM TOGGLE
* Params: * Params:
* - Strum Line which is going to be toggled (Int) * - Strum Line which is going to be toggled (Int)
* - Whenever its going to be toggled or not (Bool) * - Whenever its going to be toggled or not (Bool)
*/ */
var ALT_ANIM_TOGGLE = 3; var ALT_ANIM_TOGGLE = 3;
} }
+13 -13
View File
@@ -4,19 +4,19 @@ package funkin.cutscenes;
* Substate made for cutscenes. * Substate made for cutscenes.
*/ */
class Cutscene extends MusicBeatSubstate { class Cutscene extends MusicBeatSubstate {
var __callback:Void->Void; var __callback:Void->Void;
var game:PlayState = PlayState.instance; var game:PlayState = PlayState.instance;
public function new(callback:Void->Void) { public function new(callback:Void->Void) {
super(); super();
__callback = callback; __callback = callback;
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
} }
public override function close() { public override function close() {
__callback(); __callback();
super.close(); super.close();
} }
} }
+62 -62
View File
@@ -9,78 +9,78 @@ import funkin.scripting.Script;
* To add cutscenes to your songs, add a `cutscene.hx` file in your song's directory (ex: `songs/song/cutscene.hx`) * To add cutscenes to your songs, add a `cutscene.hx` file in your song's directory (ex: `songs/song/cutscene.hx`)
*/ */
class ScriptedCutscene extends Cutscene { class ScriptedCutscene extends Cutscene {
var script:Script; var script:Script;
var scriptPath:String; var scriptPath:String;
public function new(scriptPath:String, callback:Void->Void) { public function new(scriptPath:String, callback:Void->Void) {
super(callback); super(callback);
script = Script.create(this.scriptPath = scriptPath); script = Script.create(this.scriptPath = scriptPath);
script.setPublicMap(PlayState.instance.scripts.publicVariables); script.setPublicMap(PlayState.instance.scripts.publicVariables);
script.setParent(this); script.setParent(this);
script.load(); script.load();
} }
public override function create() { public override function create() {
super.create(); super.create();
trace("fuck"); trace("fuck");
script.call("create"); script.call("create");
if (Std.isOfType(script, DummyScript)) { if (Std.isOfType(script, DummyScript)) {
Logs.trace('Could not find script for scripted cutscene at ${scriptPath}', ERROR, RED); Logs.trace('Could not find script for scripted cutscene at ${scriptPath}', ERROR, RED);
close(); close();
} }
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
script.call("update", [elapsed]); script.call("update", [elapsed]);
super.update(elapsed); super.update(elapsed);
script.call("postUpdate", [elapsed]); script.call("postUpdate", [elapsed]);
} }
public override function beatHit(curBeat:Int) { public override function beatHit(curBeat:Int) {
super.beatHit(curBeat); super.beatHit(curBeat);
script.call("beatHit", [curBeat]); script.call("beatHit", [curBeat]);
} }
public override function stepHit(curStep:Int) { public override function stepHit(curStep:Int) {
super.stepHit(curStep); super.stepHit(curStep);
script.call("stepHit", [curStep]); script.call("stepHit", [curStep]);
} }
public override function destroy() { public override function destroy() {
script.call("destroy"); script.call("destroy");
super.destroy(); super.destroy();
} }
// VIDEOS // VIDEOS
#if REGION #if REGION
public function startVideo(path:String, ?callback:Void->Void) { public function startVideo(path:String, ?callback:Void->Void) {
persistentDraw = false; persistentDraw = false;
openSubState(new VideoCutscene(path, function() { openSubState(new VideoCutscene(path, function() {
if (callback != null) if (callback != null)
callback(); callback();
})); }));
} }
public var isVideoPlaying(get, null):Bool; public var isVideoPlaying(get, null):Bool;
private inline function get_isVideoPlaying() private inline function get_isVideoPlaying()
return subState is VideoCutscene; return subState is VideoCutscene;
#end #end
// DIALOGUE // DIALOGUE
#if REGION #if REGION
public function startDialogue(path:String, ?callback:Void->Void) { public function startDialogue(path:String, ?callback:Void->Void) {
persistentDraw = true; persistentDraw = true;
openSubState(new VideoCutscene(path, function() { openSubState(new VideoCutscene(path, function() {
if (callback != null) if (callback != null)
callback(); callback();
})); }));
} }
public var isDialoguePlaying(get, null):Bool; public var isDialoguePlaying(get, null):Bool;
private inline function get_isDialoguePlaying() private inline function get_isDialoguePlaying()
return subState is DialogueCutscene; return subState is DialogueCutscene;
#end #end
} }
+43 -43
View File
@@ -5,52 +5,52 @@ package funkin.cutscenes;
* Substate made for video cutscenes. To use it in a scripted cutscene, call `startVideo`. * Substate made for video cutscenes. To use it in a scripted cutscene, call `startVideo`.
*/ */
class VideoCutscene extends Cutscene { class VideoCutscene extends Cutscene {
var path:String; var path:String;
var localPath:String; var localPath:String;
#if VIDEO_CUTSCENES #if VIDEO_CUTSCENES
var video:MP4Handler; var video:MP4Handler;
var videoSprite:FlxSprite; var videoSprite:FlxSprite;
#end #end
var cutsceneCamera:FlxCamera; var cutsceneCamera:FlxCamera;
public function new(path:String, callback:Void->Void) { public function new(path:String, callback:Void->Void) {
super(callback); super(callback);
localPath = Assets.getPath(this.path = path); localPath = Assets.getPath(this.path = path);
} }
public override function create() { public override function create() {
super.create(); super.create();
cutsceneCamera = new FlxCamera(); cutsceneCamera = new FlxCamera();
cutsceneCamera.bgColor = 0; cutsceneCamera.bgColor = 0;
FlxG.cameras.add(cutsceneCamera, false); FlxG.cameras.add(cutsceneCamera, false);
#if VIDEO_CUTSCENES #if VIDEO_CUTSCENES
video = new MP4Handler(); video = new MP4Handler();
video.finishCallback = close; video.finishCallback = close;
video.canvasWidth = cutsceneCamera.width; video.canvasWidth = cutsceneCamera.width;
video.canvasHeight = cutsceneCamera.height; video.canvasHeight = cutsceneCamera.height;
videoSprite = new FlxSprite(); videoSprite = new FlxSprite();
videoSprite.cameras = [cutsceneCamera]; videoSprite.cameras = [cutsceneCamera];
videoSprite.antialiasing = true; videoSprite.antialiasing = true;
add(videoSprite); add(videoSprite);
video.playMP4(localPath, false, videoSprite); video.playMP4(localPath, false, videoSprite);
#end #end
cameras = [cutsceneCamera]; cameras = [cutsceneCamera];
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
#if !VIDEO_CUTSCENES #if !VIDEO_CUTSCENES
close(); close();
#end #end
} }
public override function destroy() { public override function destroy() {
FlxG.cameras.remove(cutsceneCamera, true); FlxG.cameras.remove(cutsceneCamera, true);
super.destroy(); super.destroy();
} }
} }
+91 -91
View File
@@ -6,113 +6,113 @@ import flixel.math.FlxPoint;
import haxe.xml.Access; import haxe.xml.Access;
class DialogueBox extends FunkinSprite { class DialogueBox extends FunkinSprite {
public var dialogueBoxData:Access; public var dialogueBoxData:Access;
public var positions:Map<String, CharPosDef> = []; public var positions:Map<String, CharPosDef> = [];
public var textTypeSFX:String = Paths.sound('dialogue/text'); public var textTypeSFX:String = Paths.sound('dialogue/text');
public var nextSFX:String = Paths.sound('dialogue/next'); public var nextSFX:String = Paths.sound('dialogue/next');
public var text:FlxTypeText; public var text:FlxTypeText;
public function new(name:String) { public function new(name:String) {
super(); super();
try { try {
dialogueBoxData = new Access(Xml.parse(Assets.getText(Paths.xml('dialogue/boxes/$name'))).firstElement()); dialogueBoxData = new Access(Xml.parse(Assets.getText(Paths.xml('dialogue/boxes/$name'))).firstElement());
loadSprite(Paths.image('dialogue/boxes/${dialogueBoxData.getAtt('sprite').getDefault(name)}')); loadSprite(Paths.image('dialogue/boxes/${dialogueBoxData.getAtt('sprite').getDefault(name)}'));
for(anim in dialogueBoxData.nodes.anim) { for(anim in dialogueBoxData.nodes.anim) {
if (!anim.has.name) continue; if (!anim.has.name) continue;
XMLUtil.addXMLAnimation(this, anim); XMLUtil.addXMLAnimation(this, anim);
} }
for(pos in dialogueBoxData.nodes.charpos) { for(pos in dialogueBoxData.nodes.charpos) {
if (!pos.has.name) continue; if (!pos.has.name) continue;
positions[pos.att.name] = { positions[pos.att.name] = {
x: pos.has.x ? Std.parseFloat(pos.att.x).getDefault(0) : 0, x: pos.has.x ? Std.parseFloat(pos.att.x).getDefault(0) : 0,
y: pos.has.y ? Std.parseFloat(pos.att.y).getDefault(0) : 0, y: pos.has.y ? Std.parseFloat(pos.att.y).getDefault(0) : 0,
flipBubble: pos.getAtt('flipBubble') == "true" flipBubble: pos.getAtt('flipBubble') == "true"
}; };
} }
if (dialogueBoxData.has.textSound) textTypeSFX = Paths.sound(dialogueBoxData.att.textSound); if (dialogueBoxData.has.textSound) textTypeSFX = Paths.sound(dialogueBoxData.att.textSound);
if (dialogueBoxData.has.nextSound) nextSFX = Paths.sound(dialogueBoxData.att.nextSound); if (dialogueBoxData.has.nextSound) nextSFX = Paths.sound(dialogueBoxData.att.nextSound);
antialiasing = dialogueBoxData.getAtt("antialiasing").getDefault("true") == "true"; antialiasing = dialogueBoxData.getAtt("antialiasing").getDefault("true") == "true";
screenCenter(X); screenCenter(X);
y = FlxG.height - height; y = FlxG.height - height;
if (dialogueBoxData.has.x) x += Std.parseFloat(dialogueBoxData.att.x).getDefault(0); if (dialogueBoxData.has.x) x += Std.parseFloat(dialogueBoxData.att.x).getDefault(0);
if (dialogueBoxData.has.y) y += Std.parseFloat(dialogueBoxData.att.y).getDefault(0); if (dialogueBoxData.has.y) y += Std.parseFloat(dialogueBoxData.att.y).getDefault(0);
visible = false; visible = false;
var textNode = dialogueBoxData.node.text; var textNode = dialogueBoxData.node.text;
if (textNode == null) if (textNode == null)
throw "The dialog box XML requires one text element."; throw "The dialog box XML requires one text element.";
text = new FlxTypeText( text = new FlxTypeText(
textNode.has.x ? Std.parseFloat(textNode.att.x).getDefault(0) : 0, textNode.has.x ? Std.parseFloat(textNode.att.x).getDefault(0) : 0,
FlxG.height - (textNode.has.y ? Std.parseFloat(textNode.att.y).getDefault(0) : 0), FlxG.height - (textNode.has.y ? Std.parseFloat(textNode.att.y).getDefault(0) : 0),
textNode.has.width ? Std.parseInt(textNode.att.width).getDefault(FlxG.width) : FlxG.width, ""); textNode.has.width ? Std.parseInt(textNode.att.width).getDefault(FlxG.width) : FlxG.width, "");
text.color = textNode.getAtt("color").getColorFromDynamic().getDefault(0xFF000000); text.color = textNode.getAtt("color").getColorFromDynamic().getDefault(0xFF000000);
text.size = Std.parseInt(textNode.att.size).getDefault(20); text.size = Std.parseInt(textNode.att.size).getDefault(20);
text.font = Paths.font('${textNode.getAtt("font").getDefault("vcr.ttf")}'); text.font = Paths.font('${textNode.getAtt("font").getDefault("vcr.ttf")}');
text.antialiasing = textNode.getAtt("antialiasing").getDefault("false") == "true"; text.antialiasing = textNode.getAtt("antialiasing").getDefault("false") == "true";
text.sounds = [FlxG.sound.load(textTypeSFX)]; text.sounds = [FlxG.sound.load(textTypeSFX)];
} catch(e) { } catch(e) {
active = false; active = false;
Logs.trace('Couldn\'t load dialogue box "$name": ${e.toString()}', ERROR); Logs.trace('Couldn\'t load dialogue box "$name": ${e.toString()}', ERROR);
} }
FlxG.sound.cache(nextSFX); FlxG.sound.cache(nextSFX);
FlxG.sound.cache(textTypeSFX); FlxG.sound.cache(textTypeSFX);
} }
public function popupChar(char:DialogueCharacter) { public function popupChar(char:DialogueCharacter) {
if (!active) return; if (!active) return;
var pos = positions[char.positionName]; var pos = positions[char.positionName];
if (pos == null) return; if (pos == null) return;
char.show((FlxG.width / 2) + pos.x, FlxG.height - pos.y); char.show((FlxG.width / 2) + pos.x, FlxG.height - pos.y);
} }
private var __nextText:String; private var __nextText:String;
private var __speed:Float; private var __speed:Float;
public function playBubbleAnim(bubble:String, text:String, speed:Float = 0.05) { public function playBubbleAnim(bubble:String, text:String, speed:Float = 0.05) {
this.__nextText = text; this.__nextText = text;
this.__speed = speed; this.__speed = speed;
this.text.resetText(text); this.text.resetText(text);
FlxG.sound.play(nextSFX); FlxG.sound.play(nextSFX);
if (hasAnimation('$bubble-open')) if (hasAnimation('$bubble-open'))
playAnim('$bubble-open', true); playAnim('$bubble-open', true);
else { else {
playAnim(bubble); playAnim(bubble);
setText(__nextText, __speed); setText(__nextText, __speed);
} }
visible = true; visible = true;
} }
public function setText(text:String, speed:Float = 0.02) { public function setText(text:String, speed:Float = 0.02) {
this.text.delay = speed; this.text.delay = speed;
this.text.start(speed, true); this.text.start(speed, true);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (isAnimFinished()) { if (isAnimFinished()) {
var animName = getAnimName(); var animName = getAnimName();
if (animName.endsWith("-open")) { if (animName.endsWith("-open")) {
playAnim(animName.substr(0, animName.length - 5)); playAnim(animName.substr(0, animName.length - 5));
setText(__nextText, __speed); setText(__nextText, __speed);
} }
} }
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
positions = null; positions = null;
} }
} }
typedef CharPosDef = { typedef CharPosDef = {
var x:Float; var x:Float;
var y:Float; var y:Float;
var flipBubble:Bool; var flipBubble:Bool;
} }
@@ -4,56 +4,56 @@ import flixel.tweens.FlxTween;
import haxe.xml.Access; import haxe.xml.Access;
class DialogueCharacter extends FunkinSprite { class DialogueCharacter extends FunkinSprite {
public var charData:Access; public var charData:Access;
public var curTween:FlxTween; public var curTween:FlxTween;
public var curTweenContext:DialogueCharTweenContext = NONE; public var curTweenContext:DialogueCharTweenContext = NONE;
public var positionName:String; public var positionName:String;
public function new(name:String, position:String) { public function new(name:String, position:String) {
super(); super();
this.positionName = position; this.positionName = position;
try { try {
charData = new Access(Xml.parse(Assets.getText(Paths.xml('dialogue/characters/$name'))).firstElement()); charData = new Access(Xml.parse(Assets.getText(Paths.xml('dialogue/characters/$name'))).firstElement());
loadSprite(Paths.image('dialogue/characters/${charData.getAtt('sprite').getDefault(name)}')); loadSprite(Paths.image('dialogue/characters/${charData.getAtt('sprite').getDefault(name)}'));
antialiasing = charData.getAtt('antialiasing').getDefault('true') == 'true'; antialiasing = charData.getAtt('antialiasing').getDefault('true') == 'true';
scale.scale(charData.has.scale ? Std.parseFloat(charData.att.scale).getDefault(1) : 1); scale.scale(charData.has.scale ? Std.parseFloat(charData.att.scale).getDefault(1) : 1);
updateHitbox(); updateHitbox();
offset.set( offset.set(
charData.has.x ? Std.parseFloat(charData.att.x).getDefault(0) : 0, charData.has.x ? Std.parseFloat(charData.att.x).getDefault(0) : 0,
(charData.has.y ? Std.parseFloat(charData.att.y).getDefault(0) : 0) + this.height); (charData.has.y ? Std.parseFloat(charData.att.y).getDefault(0) : 0) + this.height);
for(anim in charData.nodes.anim) for(anim in charData.nodes.anim)
XMLUtil.addXMLAnimation(this, anim, true); XMLUtil.addXMLAnimation(this, anim, true);
} catch(e) { } catch(e) {
Logs.trace('Failed to load dialogue character $name: ${e.toString()}', ERROR); Logs.trace('Failed to load dialogue character $name: ${e.toString()}', ERROR);
} }
visible = false; visible = false;
} }
public function show(x:Float, y:Float) { public function show(x:Float, y:Float) {
if (curTweenContext != (curTweenContext = POPIN)) { if (curTweenContext != (curTweenContext = POPIN)) {
setPosition(x, y + 100); setPosition(x, y + 100);
if (curTween != null) if (curTween != null)
curTween.cancel(); curTween.cancel();
alpha = 0; alpha = 0;
visible = true; visible = true;
curTween = FlxTween.tween(this, {alpha: 1, y: y}, 0.2, {ease: FlxEase.quintOut}); curTween = FlxTween.tween(this, {alpha: 1, y: y}, 0.2, {ease: FlxEase.quintOut});
} }
} }
public function hide() { public function hide() {
if (curTweenContext != (curTweenContext = POPOUT)) { if (curTweenContext != (curTweenContext = POPOUT)) {
if (curTween != null) if (curTween != null)
curTween.cancel(); curTween.cancel();
curTween = FlxTween.tween(this, {alpha: 0, y: y + 100}, 0.2, {ease: FlxEase.quintIn}); curTween = FlxTween.tween(this, {alpha: 0, y: y + 100}, 0.2, {ease: FlxEase.quintIn});
} }
} }
} }
enum abstract DialogueCharTweenContext(Int) { enum abstract DialogueCharTweenContext(Int) {
var NONE = -1; var NONE = -1;
var POPIN = 0; var POPIN = 0;
var POPOUT = 1; var POPOUT = 1;
} }
+28 -28
View File
@@ -6,43 +6,43 @@ import funkin.options.TreeMenu;
import funkin.windows.WindowsAPI; import funkin.windows.WindowsAPI;
class DebugOptions extends TreeMenu { class DebugOptions extends TreeMenu {
public override function create() { public override function create() {
super.create(); super.create();
FlxG.camera.fade(0xFF000000, 0.5, true); FlxG.camera.fade(0xFF000000, 0.5, true);
var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue')); var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue'));
// bg.scrollFactor.set(); // bg.scrollFactor.set();
bg.scale.set(1.15, 1.15); bg.scale.set(1.15, 1.15);
bg.updateHitbox(); bg.updateHitbox();
bg.screenCenter(); bg.screenCenter();
bg.scrollFactor.set(); bg.scrollFactor.set();
bg.antialiasing = true; bg.antialiasing = true;
add(bg); add(bg);
main = new DebugOptionsScreen(); main = new DebugOptionsScreen();
} }
} }
class DebugOptionsScreen extends OptionsScreen { class DebugOptionsScreen extends OptionsScreen {
public override function new() { public override function new() {
super("Debug Options", "Use this menu to change debug options."); super("Debug Options", "Use this menu to change debug options.");
#if windows #if windows
add(new TextOption( add(new TextOption(
"Show Console", "Show Console",
"Select this to show the debug console, which contains log information about the game.", "Select this to show the debug console, which contains log information about the game.",
function() { function() {
WindowsAPI.allocConsole(); WindowsAPI.allocConsole();
})); }));
add(new Checkbox( add(new Checkbox(
"Enable Editor SFXs", "Enable Editor SFXs",
"If checked, will play sound effects when working on editors (ex: will play sfxs when checking checkboxes...)", "If checked, will play sound effects when working on editors (ex: will play sfxs when checking checkboxes...)",
"editorSFX")); "editorSFX"));
add(new Checkbox( add(new Checkbox(
"Resizable Editors", "Resizable Editors",
"If checked, editors will be resizable and extensible like other programs instead of zooming in upon maximization.", "If checked, editors will be resizable and extensible like other programs instead of zooming in upon maximization.",
"resizableEditors")); "resizableEditors"));
#end #end
} }
} }
+152 -152
View File
@@ -5,199 +5,199 @@ import flixel.math.FlxPoint;
import flixel.effects.FlxFlicker; import flixel.effects.FlxFlicker;
class EditorPicker extends MusicBeatSubstate { class EditorPicker extends MusicBeatSubstate {
public var bg:FlxSprite; public var bg:FlxSprite;
public var options:Array<Editor> = [ public var options:Array<Editor> = [
{ {
name: "Chart Editor", name: "Chart Editor",
iconID: 0, iconID: 0,
state: funkin.editors.charter.CharterSelection state: funkin.editors.charter.CharterSelection
}, },
{ {
name: "Character Editor", name: "Character Editor",
iconID: 1, iconID: 1,
state: null state: null
}, },
{ {
name: "Stage Editor", name: "Stage Editor",
iconID: 2, iconID: 2,
state: null state: null
}, },
{ {
name: "UI Debug State", name: "UI Debug State",
iconID: 3, iconID: 3,
state: UIDebugState state: UIDebugState
}, },
{ {
name: "Debug Options", name: "Debug Options",
iconID: 4, iconID: 4,
state: DebugOptions state: DebugOptions
} }
]; ];
public var sprites:Array<EditorPickerOption> = []; public var sprites:Array<EditorPickerOption> = [];
public var curSelected:Int = 0; public var curSelected:Int = 0;
public var oldMousePos:FlxPoint = FlxPoint.get(); public var oldMousePos:FlxPoint = FlxPoint.get();
public var curMousePos:FlxPoint = FlxPoint.get(); public var curMousePos:FlxPoint = FlxPoint.get();
public var optionHeight:Float = 0; public var optionHeight:Float = 0;
public var selected:Bool = false; public var selected:Bool = false;
public var camVelocity:Float = 0; public var camVelocity:Float = 0;
public override function create() { public override function create() {
super.create(); super.create();
camera = new FlxCamera(); camera = new FlxCamera();
camera.bgColor = 0; camera.bgColor = 0;
FlxG.cameras.add(camera, false); FlxG.cameras.add(camera, false);
bg = new FlxSprite().makeGraphic(1, 1, 0xFF000000); bg = new FlxSprite().makeGraphic(1, 1, 0xFF000000);
bg.scrollFactor.set(); bg.scrollFactor.set();
bg.scale.set(FlxG.width, FlxG.height); bg.scale.set(FlxG.width, FlxG.height);
bg.updateHitbox(); bg.updateHitbox();
bg.alpha = 0; bg.alpha = 0;
add(bg); add(bg);
optionHeight = FlxG.height / options.length; optionHeight = FlxG.height / options.length;
for(k=>o in options) { for(k=>o in options) {
var spr = new EditorPickerOption(o.name, o.iconID, optionHeight); var spr = new EditorPickerOption(o.name, o.iconID, optionHeight);
spr.y = k * optionHeight; spr.y = k * optionHeight;
add(spr); add(spr);
sprites.push(spr); sprites.push(spr);
} }
sprites[0].selected = true; sprites[0].selected = true;
FlxG.mouse.getScreenPosition(camera, oldMousePos); FlxG.mouse.getScreenPosition(camera, oldMousePos);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
bg.alpha = CoolUtil.fpsLerp(bg.alpha, selected ? 1 : 0.5, 0.25); bg.alpha = CoolUtil.fpsLerp(bg.alpha, selected ? 1 : 0.5, 0.25);
if (selected) { if (selected) {
camVelocity += FlxG.width * elapsed * 2; camVelocity += FlxG.width * elapsed * 2;
camera.scroll.x += camVelocity * elapsed; camera.scroll.x += camVelocity * elapsed;
return; return;
} }
changeSelection(-FlxG.mouse.wheel + (controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0)); changeSelection(-FlxG.mouse.wheel + (controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0));
FlxG.mouse.getScreenPosition(camera, curMousePos); FlxG.mouse.getScreenPosition(camera, curMousePos);
if (curMousePos.x != oldMousePos.x || curMousePos.y != oldMousePos.y) { if (curMousePos.x != oldMousePos.x || curMousePos.y != oldMousePos.y) {
oldMousePos.set(curMousePos.x, curMousePos.y); oldMousePos.set(curMousePos.x, curMousePos.y);
curSelected = -1; curSelected = -1;
changeSelection(Std.int(curMousePos.y / optionHeight)+1); changeSelection(Std.int(curMousePos.y / optionHeight)+1);
} }
if (controls.ACCEPT || FlxG.mouse.justReleased) { if (controls.ACCEPT || FlxG.mouse.justReleased) {
selected = true; selected = true;
CoolUtil.playMenuSFX(CONFIRM); CoolUtil.playMenuSFX(CONFIRM);
FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransIn = true;
FlxTransitionableState.skipNextTransOut = true; FlxTransitionableState.skipNextTransOut = true;
FlxG.sound.music.fadeOut(0.7, 0, function(n) { FlxG.sound.music.fadeOut(0.7, 0, function(n) {
FlxG.sound.music.stop(); FlxG.sound.music.stop();
}); });
sprites[curSelected].flicker(function() { sprites[curSelected].flicker(function() {
if (FlxG.sound.music != null) if (FlxG.sound.music != null)
camera.fade(0xFF000000, 0.25, false, function() { camera.fade(0xFF000000, 0.25, false, function() {
FlxG.switchState(Type.createInstance(options[curSelected].state, [])); FlxG.switchState(Type.createInstance(options[curSelected].state, []));
}); });
}); });
} }
if (controls.BACK) if (controls.BACK)
close(); close();
} }
public function changeSelection(change:Int) { public function changeSelection(change:Int) {
if (change == 0) return; if (change == 0) return;
curSelected = FlxMath.wrap(curSelected + change, 0, sprites.length-1); curSelected = FlxMath.wrap(curSelected + change, 0, sprites.length-1);
for(o in sprites) for(o in sprites)
o.selected = false; o.selected = false;
sprites[curSelected].selected = true; sprites[curSelected].selected = true;
} }
} }
typedef Editor = { typedef Editor = {
var name:String; var name:String;
var iconID:Int; var iconID:Int;
var state:Class<MusicBeatState>; var state:Class<MusicBeatState>;
} }
class EditorPickerOption extends FlxTypedSpriteGroup<FlxSprite> { class EditorPickerOption extends FlxTypedSpriteGroup<FlxSprite> {
public var iconSpr:FlxSprite; public var iconSpr:FlxSprite;
public var label:Alphabet; public var label:Alphabet;
public var selectionBG:FlxSprite; public var selectionBG:FlxSprite;
public var selected:Bool = false; public var selected:Bool = false;
public var selectionLerp:Float = 0; public var selectionLerp:Float = 0;
public var iconRotationCycle:Float = 0; public var iconRotationCycle:Float = 0;
public function new(name:String, iconID:Int, height:Float) { public function new(name:String, iconID:Int, height:Float) {
super(); super();
FlxG.mouse.visible = true; FlxG.mouse.visible = true;
iconSpr = new FlxSprite(); iconSpr = new FlxSprite();
iconSpr.loadGraphic(Paths.image('editors/icons'), true, 128, 128); iconSpr.loadGraphic(Paths.image('editors/icons'), true, 128, 128);
iconSpr.animation.add("icon", [iconID], 24, true); iconSpr.animation.add("icon", [iconID], 24, true);
iconSpr.animation.play("icon"); iconSpr.animation.play("icon");
iconSpr.antialiasing = true; iconSpr.antialiasing = true;
if (height < 150) { if (height < 150) {
iconSpr.scale.set(height / 150, height / 150); iconSpr.scale.set(height / 150, height / 150);
iconSpr.updateHitbox(); iconSpr.updateHitbox();
} }
iconSpr.x = 25 + ((height - iconSpr.width) / 2); iconSpr.x = 25 + ((height - iconSpr.width) / 2);
iconSpr.y = (height - iconSpr.height) / 2; iconSpr.y = (height - iconSpr.height) / 2;
label = new Alphabet(25 + iconSpr.width + 25, 0, name, true); label = new Alphabet(25 + iconSpr.width + 25, 0, name, true);
label.y = (height - label.height) / 2; label.y = (height - label.height) / 2;
selectionBG = new FlxSprite().makeGraphic(1, 1, -1); selectionBG = new FlxSprite().makeGraphic(1, 1, -1);
selectionBG.scale.set(FlxG.width, height); selectionBG.scale.set(FlxG.width, height);
selectionBG.updateHitbox(); selectionBG.updateHitbox();
selectionBG.alpha = 0; selectionBG.alpha = 0;
add(selectionBG); add(selectionBG);
add(iconSpr); add(iconSpr);
add(label); add(label);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
iconRotationCycle += elapsed; iconRotationCycle += elapsed;
selectionLerp = CoolUtil.fpsLerp(selectionLerp, selected ? 1 : 0, 0.25); selectionLerp = CoolUtil.fpsLerp(selectionLerp, selected ? 1 : 0, 0.25);
selectionBG.alpha = (iconSpr.alpha = FlxEase.cubeOut(selectionLerp)) * 0.5; selectionBG.alpha = (iconSpr.alpha = FlxEase.cubeOut(selectionLerp)) * 0.5;
selectionBG.x = FlxMath.lerp(-FlxG.width, 0, selectionLerp); selectionBG.x = FlxMath.lerp(-FlxG.width, 0, selectionLerp);
label.x = FlxMath.lerp(10, 25 + iconSpr.width + 25, selectionLerp); label.x = FlxMath.lerp(10, 25 + iconSpr.width + 25, selectionLerp);
iconSpr.x = label.x - 25 - iconSpr.width; iconSpr.x = label.x - 25 - iconSpr.width;
iconSpr.angle = Math.sin(iconRotationCycle * 0.5) * 5; iconSpr.angle = Math.sin(iconRotationCycle * 0.5) * 5;
scrollFactor.set(FlxMath.lerp(1, 0.1, selectionLerp), 0); scrollFactor.set(FlxMath.lerp(1, 0.1, selectionLerp), 0);
selectionBG.scrollFactor.set(0, 0); selectionBG.scrollFactor.set(0, 0);
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
} }
public function flicker(callback:Void->Void) { public function flicker(callback:Void->Void) {
FlxFlicker.flicker(label, 0.5, Options.flashingMenu ? 0.06 : 0.15, false, false, function(t) { FlxFlicker.flicker(label, 0.5, Options.flashingMenu ? 0.06 : 0.15, false, false, function(t) {
callback(); callback();
}); });
} }
} }
+15 -15
View File
@@ -5,27 +5,27 @@ import flixel.addons.display.FlxBackdrop;
import funkin.options.*; import funkin.options.*;
class EditorTreeMenu extends TreeMenu { class EditorTreeMenu extends TreeMenu {
public var bg:FlxBackdrop; public var bg:FlxBackdrop;
public var bgType:String = "default"; public var bgType:String = "default";
public override function create() { public override function create() {
super.create(); super.create();
FlxG.camera.fade(0xFF000000, 0.5, true); FlxG.camera.fade(0xFF000000, 0.5, true);
bg = new FlxBackdrop(); bg = new FlxBackdrop();
bg.loadGraphic(Paths.image('editors/bgs/${bgType}')); bg.loadGraphic(Paths.image('editors/bgs/${bgType}'));
bg.antialiasing = true; bg.antialiasing = true;
add(bg); add(bg);
} }
public override function exit() { public override function exit() {
FlxG.switchState(new MainMenuState()); FlxG.switchState(new MainMenuState());
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
bg.x += elapsed * 125; bg.x += elapsed * 125;
bg.y += elapsed * 125; bg.y += elapsed * 125;
} }
} }
+122 -122
View File
@@ -3,132 +3,132 @@ package funkin.editors;
import funkin.editors.ui.*; import funkin.editors.ui.*;
class UIDebugState extends UIState { class UIDebugState extends UIState {
public override function create() { public override function create() {
super.create(); super.create();
FlxG.mouse.useSystemCursor = FlxG.mouse.visible = true; FlxG.mouse.useSystemCursor = FlxG.mouse.visible = true;
var bg = new FlxSprite().makeGraphic(1, 1, 0xFF444444); var bg = new FlxSprite().makeGraphic(1, 1, 0xFF444444);
bg.scale.set(FlxG.width, FlxG.height); bg.scale.set(FlxG.width, FlxG.height);
bg.updateHitbox(); bg.updateHitbox();
bg.scrollFactor.set(); bg.scrollFactor.set();
add(bg); add(bg);
add(new UITopMenu([ add(new UITopMenu([
{ {
label: "File", label: "File",
childs: [ childs: [
{ {
label: "New" label: "New"
}, },
{ {
label: "Open" label: "Open"
}, },
{ {
label: "Save" label: "Save"
}, },
{ {
label: "Save As..." label: "Save As..."
}, },
null, null,
{ {
label: "Exit", label: "Exit",
onSelect: (t) -> {FlxG.switchState(new funkin.menus.MainMenuState());} onSelect: (t) -> {FlxG.switchState(new funkin.menus.MainMenuState());}
} }
] ]
}, },
{ {
label: "Edit" label: "Edit"
}, },
{ {
label: "View" label: "View"
}, },
{ {
label: "Help" label: "Help"
} }
])); ]));
add(new UICheckbox(10, 40, "Test unchecked", false)); add(new UICheckbox(10, 40, "Test unchecked", false));
add(new UICheckbox(10, 70, "Test checked", true)); add(new UICheckbox(10, 70, "Test checked", true));
add(new UIButton(10, 100, "Test button", function() { add(new UIButton(10, 100, "Test button", function() {
trace("Hello, World!"); trace("Hello, World!");
}, 130, 32)); }, 130, 32));
add(new UIButton(10, 140, "Warning test", function() { add(new UIButton(10, 140, "Warning test", function() {
openSubState(new UIWarningSubstate("Test", "This is a test message", [ openSubState(new UIWarningSubstate("Test", "This is a test message", [
{ {
label: "Alt. Choice", label: "Alt. Choice",
onClick: function(t) { onClick: function(t) {
trace("Alt. Choice clicked!"); trace("Alt. Choice clicked!");
} }
}, },
{ {
label: "OK", label: "OK",
onClick: function(t) { onClick: function(t) {
} }
} }
])); ]));
}, 130, 32)); }, 130, 32));
add(new UIButton(10, 180, "Warning test (Overflowing)", function() { add(new UIButton(10, 180, "Warning test (Overflowing)", function() {
openSubState(new UIWarningSubstate("Test", "This is a test message", [ openSubState(new UIWarningSubstate("Test", "This is a test message", [
{ {
label: "Alt. Choice", label: "Alt. Choice",
onClick: function(t) { onClick: function(t) {
trace("Alt. Choice clicked!"); trace("Alt. Choice clicked!");
} }
}, },
{ {
label: "OK", label: "OK",
onClick: function(t) {} onClick: function(t) {}
}, },
{ {
label: "1", label: "1",
onClick: function(t) {} onClick: function(t) {}
}, },
{ {
label: "2", label: "2",
onClick: function(t) {} onClick: function(t) {}
}, },
{ {
label: "3", label: "3",
onClick: function(t) {} onClick: function(t) {}
}, },
{ {
label: "4", label: "4",
onClick: function(t) {} onClick: function(t) {}
} }
])); ]));
}, 130, 48)); }, 130, 48));
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (FlxG.mouse.justReleasedRight) { if (FlxG.mouse.justReleasedRight) {
openContextMenu([ openContextMenu([
{ {
label: "Test 1", label: "Test 1",
onSelect: function(t) { onSelect: function(t) {
trace("Test 1 clicked"); trace("Test 1 clicked");
} }
}, },
{ {
label: "Test 2", label: "Test 2",
onSelect: function(t) { onSelect: function(t) {
trace("Test 2 clicked"); trace("Test 2 clicked");
} }
}, },
{ {
label: "Test 3", label: "Test 3",
childs: [ childs: [
{ {
label: "Test 4", label: "Test 4",
onSelect: function(t) { onSelect: function(t) {
trace("Test 4 clicked"); trace("Test 4 clicked");
} }
} }
] ]
} }
]); ]);
} }
} }
} }
+37 -37
View File
@@ -6,32 +6,32 @@ import funkin.shaders.CustomShader;
import flixel.util.FlxColor; import flixel.util.FlxColor;
class CharterNote extends UISprite { class CharterNote extends UISprite {
var angleTween:FlxTween; var angleTween:FlxTween;
public var selected:Bool = false; public var selected:Bool = false;
public function new() { public function new() {
super(); super();
antialiasing = true; antialiasing = true;
loadGraphic(Paths.image('editors/charter/note'), true, 157, 154); loadGraphic(Paths.image('editors/charter/note'), true, 157, 154);
animation.add("note", [for(i in 0...frames.frames.length) i], 0, true); animation.add("note", [for(i in 0...frames.frames.length) i], 0, true);
animation.play("note"); animation.play("note");
this.setUnstretchedGraphicSize(40, 40, false); this.setUnstretchedGraphicSize(40, 40, false);
angle = 45; // green-red inbetween angle = 45; // green-red inbetween
cursor = BUTTON; cursor = BUTTON;
moves = false; moves = false;
} }
public override function updateButton() { public override function updateButton() {
__rect.x = x; __rect.x = x;
__rect.y = y; __rect.y = y;
__rect.width = 40; __rect.width = 40;
__rect.height = 40; __rect.height = 40;
UIState.state.updateRectButtonHandler(this, __rect, onHovered); UIState.state.updateRectButtonHandler(this, __rect, onHovered);
} }
public var step:Float; public var step:Float;
@@ -39,27 +39,27 @@ class CharterNote extends UISprite {
public var susLength:Float; public var susLength:Float;
public var type:Int; public var type:Int;
public function updatePos(step:Float, id:Int, susLength:Float = 0, type:Int = 0) { public function updatePos(step:Float, id:Int, susLength:Float = 0, type:Int = 0) {
this.step = step; this.step = step;
this.id = id; this.id = id;
this.susLength = susLength; this.susLength = susLength;
this.type = type; this.type = type;
x = id * 40; x = id * 40;
y = step * 40; y = step * 40;
if (angleTween != null) angleTween.cancel(); if (angleTween != null) angleTween.cancel();
angleTween = FlxTween.tween(this, {angle: switch(animation.curAnim.curFrame = (id % 4)) { angleTween = FlxTween.tween(this, {angle: switch(animation.curAnim.curFrame = (id % 4)) {
case 0: -90; case 0: -90;
case 1: 180; case 1: 180;
case 2: 0; case 2: 0;
case 3: 90; case 3: 90;
default: 0; // how is that even possible default: 0; // how is that even possible
}}, 2/3, {ease: function(t) { }}, 2/3, {ease: function(t) {
return ((Math.sin(t * Math.PI) * 0.35) * 3 * t * Math.sqrt(1 - t)) + t; return ((Math.sin(t * Math.PI) * 0.35) * 3 * t * Math.sqrt(1 - t)) + t;
}}); }});
} }
public override function kill() { public override function kill() {
if (angleTween != null) { if (angleTween != null) {
@@ -76,7 +76,7 @@ class CharterNote extends UISprite {
} }
var __passed:Bool = false; var __passed:Bool = false;
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (__passed != (__passed = step < Conductor.curStepFloat)) { if (__passed != (__passed = step < Conductor.curStepFloat)) {
@@ -85,8 +85,8 @@ class CharterNote extends UISprite {
Charter.instance.hitsound.replay(); Charter.instance.hitsound.replay();
} }
colorTransform.redMultiplier = colorTransform.greenMultiplier = colorTransform.blueMultiplier = selected ? 0.75 : 1; colorTransform.redMultiplier = colorTransform.greenMultiplier = colorTransform.blueMultiplier = selected ? 0.75 : 1;
colorTransform.redOffset = colorTransform.greenOffset = selected ? 96 : 0; colorTransform.redOffset = colorTransform.greenOffset = selected ? 96 : 0;
colorTransform.blueOffset = selected ? 168 : 0; colorTransform.blueOffset = selected ? 168 : 0;
} }
} }
@@ -3,48 +3,48 @@ package funkin.editors.charter;
import funkin.system.Conductor; import funkin.system.Conductor;
class CharterNoteGroup extends FlxTypedGroup<CharterNote> { class CharterNoteGroup extends FlxTypedGroup<CharterNote> {
var __loopSprite:CharterNote; var __loopSprite:CharterNote;
var i:Int = 0; var i:Int = 0;
var max:Float = 0; var max:Float = 0;
var __currentlyLooping:Bool = false; var __currentlyLooping:Bool = false;
public override function forEach(noteFunc:CharterNote->Void, recursive:Bool = false) { public override function forEach(noteFunc:CharterNote->Void, recursive:Bool = false) {
i = 0; i = 0;
__loopSprite = null; __loopSprite = null;
max = FlxG.height / 70 / camera.zoom; max = FlxG.height / 70 / camera.zoom;
var oldCur = __currentlyLooping; var oldCur = __currentlyLooping;
__currentlyLooping = true; __currentlyLooping = true;
while(i < length) { while(i < length) {
__loopSprite = members[i]; __loopSprite = members[i];
if (__loopSprite == null || !__loopSprite.exists) { if (__loopSprite == null || !__loopSprite.exists) {
i++; i++;
continue; continue;
} }
if (Math.abs(__loopSprite.step - Conductor.curStepFloat) < max) if (Math.abs(__loopSprite.step - Conductor.curStepFloat) < max)
noteFunc(__loopSprite); noteFunc(__loopSprite);
i++; i++;
} }
__currentlyLooping = oldCur; __currentlyLooping = oldCur;
} }
public override function draw() { public override function draw() {
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras; @:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
@:privateAccess if (cameras != null) FlxCamera._defaultCameras = cameras; @:privateAccess if (cameras != null) FlxCamera._defaultCameras = cameras;
forEach((n) -> n.draw()); forEach((n) -> n.draw());
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras; @:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras; @:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
@:privateAccess if (cameras != null) FlxCamera._defaultCameras = cameras; @:privateAccess if (cameras != null) FlxCamera._defaultCameras = cameras;
forEach((n) -> n.update(elapsed)); forEach((n) -> n.update(elapsed));
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras; @:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
} }
} }
+27 -27
View File
@@ -3,38 +3,38 @@ package funkin.editors.ui;
import flixel.math.FlxPoint; import flixel.math.FlxPoint;
class UIBackdrop extends UISprite { class UIBackdrop extends UISprite {
public override function draw() { public override function draw() {
var __oldPos = FlxPoint.get(x, y); var __oldPos = FlxPoint.get(x, y);
var __oldScroll = FlxPoint.get(scrollFactor.x, scrollFactor.y); var __oldScroll = FlxPoint.get(scrollFactor.x, scrollFactor.y);
x -= camera.scroll.x * scrollFactor.x; x -= camera.scroll.x * scrollFactor.x;
y -= camera.scroll.y * scrollFactor.y; y -= camera.scroll.y * scrollFactor.y;
while(x > -width) while(x > -width)
x -= width; x -= width;
while(y > -height) while(y > -height)
y -= height; y -= height;
var defX = x; var defX = x;
while(y < FlxG.height) { while(y < FlxG.height) {
while(x < FlxG.width) { while(x < FlxG.width) {
super.drawSuper(); super.drawSuper();
x += width; x += width;
} }
y += height; y += height;
x = defX; x = defX;
} }
setPosition(__oldPos.x, __oldPos.y); setPosition(__oldPos.x, __oldPos.y);
scrollFactor.set(__oldScroll.x, __oldScroll.y); scrollFactor.set(__oldScroll.x, __oldScroll.y);
__oldPos.put(); __oldPos.put();
__oldScroll.put(); __oldScroll.put();
drawMembers(); drawMembers();
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
} }
} }
+32 -32
View File
@@ -3,42 +3,42 @@ package funkin.editors.ui;
import flixel.graphics.frames.FlxFrame; import flixel.graphics.frames.FlxFrame;
class UIButton extends UISliceSprite { class UIButton extends UISliceSprite {
public var callback:Void->Void = null; public var callback:Void->Void = null;
public var field:UIText; public var field:UIText;
public override function new(x:Float, y:Float, text:String, callback:Void->Void, w:Int = 120, h:Int = 32) { public override function new(x:Float, y:Float, text:String, callback:Void->Void, w:Int = 120, h:Int = 32) {
super(x, y, w, h, 'editors/ui/button'); super(x, y, w, h, 'editors/ui/button');
this.callback = callback; this.callback = callback;
members.push(field = new UIText(x, y, w, text)); members.push(field = new UIText(x, y, w, text));
field.borderStyle = OUTLINE; field.borderStyle = OUTLINE;
field.borderColor = 0x88000000; field.borderColor = 0x88000000;
field.borderSize = 1; field.borderSize = 1;
field.alignment = CENTER; field.alignment = CENTER;
field.fieldWidth = w; field.fieldWidth = w;
cursor = BUTTON; cursor = BUTTON;
} }
public override function resize(w:Int, h:Int) { public override function resize(w:Int, h:Int) {
super.resize(w, h); super.resize(w, h);
if (field != null) if (field != null)
field.fieldWidth = w; field.fieldWidth = w;
} }
public override function onHovered() { public override function onHovered() {
super.onHovered(); super.onHovered();
if (FlxG.mouse.justReleased && callback != null) if (FlxG.mouse.justReleased && callback != null)
callback(); callback();
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
field.follow(this, 0, (bHeight - field.height) / 2); field.follow(this, 0, (bHeight - field.height) / 2);
} }
public override function draw() { public override function draw() {
framesOffset = hovered ? (pressed ? 18 : 9) : 0; framesOffset = hovered ? (pressed ? 18 : 9) : 0;
super.draw(); super.draw();
} }
} }
+55 -55
View File
@@ -3,74 +3,74 @@ package funkin.editors.ui;
import funkin.ui.FunkinText; import funkin.ui.FunkinText;
class UICheckbox extends UISprite { class UICheckbox extends UISprite {
public var checked:Bool = false; public var checked:Bool = false;
public var onChecked:Bool->Void = null; public var onChecked:Bool->Void = null;
public var field:UIText; public var field:UIText;
public var check:FlxSprite; public var check:FlxSprite;
public function new(x:Float, y:Float, text:String, checked:Bool = false, w:Int = 0) { public function new(x:Float, y:Float, text:String, checked:Bool = false, w:Int = 0) {
super(x, y); super(x, y);
loadGraphic(Paths.image('editors/ui/checkbox'), true, 20, 20); loadGraphic(Paths.image('editors/ui/checkbox'), true, 20, 20);
for(frame=>name in ["normal", "hover", "pressed", "checkmark"]) for(frame=>name in ["normal", "hover", "pressed", "checkmark"])
animation.add(name, [frame], 0, false); animation.add(name, [frame], 0, false);
this.checked = checked; this.checked = checked;
field = new UIText(x, y, w, text); field = new UIText(x, y, w, text);
check = new FlxSprite().loadGraphicFromSprite(this); check = new FlxSprite().loadGraphicFromSprite(this);
check.animation.play("checkmark"); check.animation.play("checkmark");
members.push(check); members.push(check);
members.push(field); members.push(field);
cursor = BUTTON; cursor = BUTTON;
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
// ANIMATION HANDLING // ANIMATION HANDLING
animation.play(hovered ? (pressed ? "pressed" : "hover") : "normal"); animation.play(hovered ? (pressed ? "pressed" : "hover") : "normal");
// CHECKMARK HANDLING // CHECKMARK HANDLING
check.alpha = checked ? 1 : 0; check.alpha = checked ? 1 : 0;
check.scale.x = CoolUtil.fpsLerp(check.scale.x, 1, 0.25); check.scale.x = CoolUtil.fpsLerp(check.scale.x, 1, 0.25);
check.scale.y = CoolUtil.fpsLerp(check.scale.y, 1, 0.25); check.scale.y = CoolUtil.fpsLerp(check.scale.y, 1, 0.25);
// POSITION HANDLING // POSITION HANDLING
updatePositions(); updatePositions();
super.update(elapsed); super.update(elapsed);
} }
public inline function updatePositions() { public inline function updatePositions() {
check.follow(this); check.follow(this);
field.follow(this, 25, 0); field.follow(this, 25, 0);
} }
public override function draw() { public override function draw() {
updatePositions(); updatePositions();
super.draw(); super.draw();
} }
public override function onHovered() { public override function onHovered() {
super.onHovered(); super.onHovered();
if (FlxG.mouse.justReleased) { if (FlxG.mouse.justReleased) {
// clicked // clicked
checked = !checked; checked = !checked;
check.scale.set(1.25, 1.25); check.scale.set(1.25, 1.25);
if (Options.editorSFX) if (Options.editorSFX)
CoolUtil.playMenuSFX(checked ? CHECKED : UNCHECKED, 0.5); CoolUtil.playMenuSFX(checked ? CHECKED : UNCHECKED, 0.5);
if (onChecked != null) if (onChecked != null)
onChecked(checked); onChecked(checked);
} }
} }
public override function updateButton() { public override function updateButton() {
__rect.x = x; __rect.x = x;
__rect.y = y; __rect.y = y;
__rect.width = field.width + 30; __rect.width = field.width + 30;
__rect.height = field.height > height ? field.height : height; __rect.height = field.height > height ? field.height : height;
UIState.state.updateRectButtonHandler(this, __rect, onHovered); UIState.state.updateRectButtonHandler(this, __rect, onHovered);
} }
} }
+66 -66
View File
@@ -3,55 +3,55 @@ package funkin.editors.ui;
import flixel.graphics.frames.FlxFrame; import flixel.graphics.frames.FlxFrame;
class UISliceSprite extends UISprite { class UISliceSprite extends UISprite {
public var bWidth:Int = 120; public var bWidth:Int = 120;
public var bHeight:Int = 20; public var bHeight:Int = 20;
public var framesOffset:Int = 0; public var framesOffset:Int = 0;
public var incorporeal:Bool = false; public var incorporeal:Bool = false;
public function new(x:Float, y:Float, w:Int, h:Int, path:String) { public function new(x:Float, y:Float, w:Int, h:Int, path:String) {
super(x, y); super(x, y);
frames = CoolUtil.loadFrames(Paths.image(path)); frames = CoolUtil.loadFrames(Paths.image(path));
resize(w, h); resize(w, h);
} }
public override function updateButton() { public override function updateButton() {
if (incorporeal) return; if (incorporeal) return;
__rect.x = x; __rect.x = x;
__rect.y = y; __rect.y = y;
__rect.width = bWidth; __rect.width = bWidth;
__rect.height = bHeight; __rect.height = bHeight;
UIState.state.updateRectButtonHandler(this, __rect, onHovered); UIState.state.updateRectButtonHandler(this, __rect, onHovered);
} }
public function resize(w:Int, h:Int) { public function resize(w:Int, h:Int) {
bWidth = w; bWidth = w;
bHeight = h; bHeight = h;
} }
public override function draw() { public override function draw() {
var x:Float = this.x; var x:Float = this.x;
var y:Float = this.y; var y:Float = this.y;
var topleft:FlxFrame = frames.frames[framesOffset]; var topleft:FlxFrame = frames.frames[framesOffset];
var top:FlxFrame = frames.frames[framesOffset + 1]; var top:FlxFrame = frames.frames[framesOffset + 1];
var topright:FlxFrame = frames.frames[framesOffset + 2]; var topright:FlxFrame = frames.frames[framesOffset + 2];
var middleleft:FlxFrame = frames.frames[framesOffset + 3]; var middleleft:FlxFrame = frames.frames[framesOffset + 3];
var middle:FlxFrame = frames.frames[framesOffset + 4]; var middle:FlxFrame = frames.frames[framesOffset + 4];
var middleright:FlxFrame = frames.frames[framesOffset + 5]; var middleright:FlxFrame = frames.frames[framesOffset + 5];
var bottomleft:FlxFrame = frames.frames[framesOffset + 6]; var bottomleft:FlxFrame = frames.frames[framesOffset + 6];
var bottom:FlxFrame = frames.frames[framesOffset + 7]; var bottom:FlxFrame = frames.frames[framesOffset + 7];
var bottomright:FlxFrame = frames.frames[framesOffset + 8]; var bottomright:FlxFrame = frames.frames[framesOffset + 8];
@:privateAccess if (visible) { @:privateAccess if (visible) {
// TOP LEFT // TOP LEFT
frame = topleft; frame = topleft;
setPosition(x, y); setPosition(x, y);
__setSize(topleft.frame.width, topleft.frame.height); __setSize(topleft.frame.width, topleft.frame.height);
super.drawSuper(); super.drawSuper();
// TOP // TOP
if (bWidth > topleft.frame.width + topright.frame.width) { if (bWidth > topleft.frame.width + topright.frame.width) {
frame = top; frame = top;
setPosition(x + topleft.frame.width, y); setPosition(x + topleft.frame.width, y);
@@ -59,13 +59,13 @@ class UISliceSprite extends UISprite {
super.drawSuper(); super.drawSuper();
} }
// TOP RIGHT // TOP RIGHT
frame = topright; frame = topright;
setPosition(x + bWidth - topright.frame.width, y); setPosition(x + bWidth - topright.frame.width, y);
__setSize(topright.frame.width, topright.frame.height); __setSize(topright.frame.width, topright.frame.height);
super.drawSuper(); super.drawSuper();
// MIDDLE LEFT // MIDDLE LEFT
if (bHeight > top.frame.height + bottom.frame.height) { if (bHeight > top.frame.height + bottom.frame.height) {
frame = middleleft; frame = middleleft;
setPosition(x, y + top.frame.height); setPosition(x, y + top.frame.height);
@@ -87,12 +87,12 @@ class UISliceSprite extends UISprite {
super.drawSuper(); super.drawSuper();
} }
// BOTTOM LEFT // BOTTOM LEFT
frame = bottomleft; frame = bottomleft;
setPosition(x, y + bHeight - bottom.frame.height); setPosition(x, y + bHeight - bottom.frame.height);
__setSize(bottomleft.frame.width, bottomleft.frame.height); __setSize(bottomleft.frame.width, bottomleft.frame.height);
super.drawSuper(); super.drawSuper();
if (bWidth > bottomleft.frame.width + bottomright.frame.width) { if (bWidth > bottomleft.frame.width + bottomright.frame.width) {
// BOTTOM // BOTTOM
frame = bottom; frame = bottom;
@@ -101,20 +101,20 @@ class UISliceSprite extends UISprite {
super.drawSuper(); super.drawSuper();
} }
// BOTTOM RIGHT // BOTTOM RIGHT
frame = bottomright; frame = bottomright;
setPosition(x + bWidth - bottomright.frame.width, y + bHeight - bottom.frame.height); setPosition(x + bWidth - bottomright.frame.width, y + bHeight - bottom.frame.height);
__setSize(bottomright.frame.width, bottomright.frame.height); __setSize(bottomright.frame.width, bottomright.frame.height);
super.drawSuper(); super.drawSuper();
} }
setPosition(x, y); setPosition(x, y);
super.drawMembers(); super.drawMembers();
} }
private function __setSize(Width:Float, Height:Float) { private function __setSize(Width:Float, Height:Float) {
var newScaleX:Float = Width / frameWidth; var newScaleX:Float = Width / frameWidth;
var newScaleY:Float = Height / frameHeight; var newScaleY:Float = Height / frameHeight;
scale.set(newScaleX, newScaleY); scale.set(newScaleX, newScaleY);
@@ -123,6 +123,6 @@ class UISliceSprite extends UISprite {
else if (Height <= 0) else if (Height <= 0)
scale.y = newScaleX; scale.y = newScaleX;
updateHitbox(); updateHitbox();
} }
} }
+60 -60
View File
@@ -7,80 +7,80 @@ import openfl.ui.MouseCursor;
@:allow(funkin.editors.ui.UIState) @:allow(funkin.editors.ui.UIState)
@:allow(funkin.editors.ui.UIUtil) @:allow(funkin.editors.ui.UIUtil)
class UISprite extends FlxSprite { class UISprite extends FlxSprite {
public var members:Array<FlxBasic> = []; public var members:Array<FlxBasic> = [];
private var __lastDrawCameras:Array<FlxCamera> = []; private var __lastDrawCameras:Array<FlxCamera> = [];
private var __rect:FlxRect = new FlxRect(); private var __rect:FlxRect = new FlxRect();
private var __oldDefCams:Array<FlxCamera>; private var __oldDefCams:Array<FlxCamera>;
public var hovered:Bool = false; public var hovered:Bool = false;
public var hoveredByChild:Bool = false; public var hoveredByChild:Bool = false;
public var pressed:Bool = false; public var pressed:Bool = false;
public var hoverCallback:Void->Void = null; public var hoverCallback:Void->Void = null;
public var cursor:MouseCursor = ARROW; public var cursor:MouseCursor = ARROW;
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
hovered = false; hovered = false;
pressed = false; pressed = false;
hoveredByChild = false; hoveredByChild = false;
super.update(elapsed); super.update(elapsed);
updateButton(); updateButton();
@:privateAccess { @:privateAccess {
__oldDefCams = FlxCamera._defaultCameras; __oldDefCams = FlxCamera._defaultCameras;
FlxCamera._defaultCameras = cameras; FlxCamera._defaultCameras = cameras;
for(m in members) for(m in members)
m.update(elapsed); m.update(elapsed);
FlxCamera._defaultCameras = __oldDefCams; FlxCamera._defaultCameras = __oldDefCams;
} }
} }
public override function draw() { public override function draw() {
drawSuper(); drawSuper();
drawMembers(); drawMembers();
} }
public function drawSuper() { public function drawSuper() {
super.draw(); super.draw();
__lastDrawCameras = [for(c in cameras) c]; __lastDrawCameras = [for(c in cameras) c];
} }
public function drawMembers() { public function drawMembers() {
@:privateAccess { @:privateAccess {
__oldDefCams = FlxCamera._defaultCameras; __oldDefCams = FlxCamera._defaultCameras;
FlxCamera._defaultCameras = cameras; FlxCamera._defaultCameras = cameras;
for(m in members) for(m in members)
m.draw(); m.draw();
FlxCamera._defaultCameras = __oldDefCams; FlxCamera._defaultCameras = __oldDefCams;
} }
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
members = FlxDestroyUtil.destroyArray(members); members = FlxDestroyUtil.destroyArray(members);
} }
public function updateButton() { public function updateButton() {
UIState.state.updateButtonHandler(this, onHovered); UIState.state.updateButtonHandler(this, onHovered);
} }
/** /**
* Called whenever the sprite is being hovered by the mouse. * Called whenever the sprite is being hovered by the mouse.
*/ */
public function onHovered() { public function onHovered() {
hovered = true; hovered = true;
if (FlxG.mouse.pressed) if (FlxG.mouse.pressed)
pressed = true; pressed = true;
if (hoverCallback != null) if (hoverCallback != null)
hoverCallback(); hoverCallback();
} }
} }
+5 -5
View File
@@ -4,9 +4,9 @@ import flixel.util.FlxColor;
import funkin.ui.FunkinText; import funkin.ui.FunkinText;
class UIText extends FunkinText { class UIText extends FunkinText {
// PUTTING THIS HERE IN CASE IMMA MAKE FUTURE CHANGES // PUTTING THIS HERE IN CASE IMMA MAKE FUTURE CHANGES
public function new(x, y, w, text, size:Int = 15, color:FlxColor = 0xFFFFFFFF) { public function new(x, y, w, text, size:Int = 15, color:FlxColor = 0xFFFFFFFF) {
super(x, y, w, text, size, false); super(x, y, w, text, size, false);
this.color = color; this.color = color;
} }
} }
+58 -58
View File
@@ -3,74 +3,74 @@ package funkin.editors.ui;
import funkin.editors.ui.UIContextMenu.UIContextMenuOption; import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
class UITopMenu extends UISliceSprite { class UITopMenu extends UISliceSprite {
var options:Array<UIContextMenuOption>; var options:Array<UIContextMenuOption>;
public function new(options:Array<UIContextMenuOption>) { public function new(options:Array<UIContextMenuOption>) {
this.options = options; this.options = options;
super(0, 0, FlxG.width, 25, 'editors/ui/topmenu'); super(0, 0, FlxG.width, 25, 'editors/ui/topmenu');
scrollFactor.set(0, 0); scrollFactor.set(0, 0);
var x:Int = 0; var x:Int = 0;
for(o in options) { for(o in options) {
var b = new UITopMenuButton(x, 0, this, o.label, o.childs); var b = new UITopMenuButton(x, 0, this, o.label, o.childs);
x += b.bWidth; x += b.bWidth;
members.push(b); members.push(b);
} }
} }
public var anyMenuOpened:Bool = false; public var anyMenuOpened:Bool = false;
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
anyMenuOpened = false; anyMenuOpened = false;
for(c in members) if (cast(c, UITopMenuButton).curMenu.contextMenuOpened()) { for(c in members) if (cast(c, UITopMenuButton).curMenu.contextMenuOpened()) {
anyMenuOpened = true; anyMenuOpened = true;
break; break;
} }
super.update(elapsed); super.update(elapsed);
bWidth = FlxG.width; bWidth = FlxG.width;
} }
} }
class UITopMenuButton extends UISliceSprite { class UITopMenuButton extends UISliceSprite {
public var label:UIText; public var label:UIText;
public var contextMenu:Array<UIContextMenuOption>; public var contextMenu:Array<UIContextMenuOption>;
public var parent:UITopMenu; public var parent:UITopMenu;
public var curMenu:UIContextMenu = null; public var curMenu:UIContextMenu = null;
public function new(x:Float, y:Float, parent:UITopMenu, label:String, contextMenu:Array<UIContextMenuOption>) { public function new(x:Float, y:Float, parent:UITopMenu, label:String, contextMenu:Array<UIContextMenuOption>) {
super(x, y, 0, 23, "editors/ui/menu-item"); super(x, y, 0, 23, "editors/ui/menu-item");
this.contextMenu = contextMenu; this.contextMenu = contextMenu;
this.parent = parent; this.parent = parent;
cursor = BUTTON; cursor = BUTTON;
this.label = new UIText(4, 0, 0, label); this.label = new UIText(4, 0, 0, label);
this.label.alignment = CENTER; this.label.alignment = CENTER;
bWidth = this.label.frameWidth + 8; bWidth = this.label.frameWidth + 8;
members.push(this.label); members.push(this.label);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
label.follow(this, 4, Std.int((bHeight - label.height) / 2)); label.follow(this, 4, Std.int((bHeight - label.height) / 2));
super.update(elapsed); super.update(elapsed);
var opened = curMenu.contextMenuOpened(); var opened = curMenu.contextMenuOpened();
alpha = (hovered || opened) ? 1 : 0; alpha = (hovered || opened) ? 1 : 0;
framesOffset = opened ? 9 : 0; framesOffset = opened ? 9 : 0;
} }
public override function onHovered() { public override function onHovered() {
super.onHovered(); super.onHovered();
if (hovered) { if (hovered) {
if (curMenu.contextMenuOpened()) { if (curMenu.contextMenuOpened()) {
UIState.state.curContextMenu.preventOutOfBoxClickDeletion(); UIState.state.curContextMenu.preventOutOfBoxClickDeletion();
} else { } else {
if (parent.anyMenuOpened || FlxG.mouse.justReleased) { if (parent.anyMenuOpened || FlxG.mouse.justReleased) {
curMenu = UIState.state.openContextMenu(contextMenu, null, x, y + bHeight); curMenu = UIState.state.openContextMenu(contextMenu, null, x, y + bHeight);
} }
} }
} }
} }
} }
+60 -60
View File
@@ -5,82 +5,82 @@ import flixel.tweens.FlxEase;
import funkin.shaders.CustomShader; import funkin.shaders.CustomShader;
class UIWarningSubstate extends MusicBeatSubstate { class UIWarningSubstate extends MusicBeatSubstate {
var camShaders:Array<FlxCamera> = []; var camShaders:Array<FlxCamera> = [];
var blurShader:CustomShader = new CustomShader("engine/editorBlur"); var blurShader:CustomShader = new CustomShader("engine/editorBlur");
var title:String; var title:String;
var message:String; var message:String;
var buttons:Array<WarningButton>; var buttons:Array<WarningButton>;
var titleSpr:UIText; var titleSpr:UIText;
var messageSpr:UIText; var messageSpr:UIText;
var warnCam:FlxCamera; var warnCam:FlxCamera;
public override function onSubstateOpen() { public override function onSubstateOpen() {
super.onSubstateOpen(); super.onSubstateOpen();
parent.persistentUpdate = false; parent.persistentUpdate = false;
parent.persistentDraw = true; parent.persistentDraw = true;
} }
public override function create() { public override function create() {
for(c in FlxG.cameras.list) { for(c in FlxG.cameras.list) {
camShaders.push(c); camShaders.push(c);
c.addShader(blurShader); c.addShader(blurShader);
} }
camera = warnCam = new FlxCamera(); camera = warnCam = new FlxCamera();
warnCam.bgColor = 0; warnCam.bgColor = 0;
warnCam.alpha = 0; warnCam.alpha = 0;
warnCam.zoom = 0.1; warnCam.zoom = 0.1;
FlxG.cameras.add(warnCam, false); FlxG.cameras.add(warnCam, false);
var spr = new UISliceSprite(0, 0, CoolUtil.maxInt(560, 30 + (170 * buttons.length)), 280, "editors/ui/warning-popup"); var spr = new UISliceSprite(0, 0, CoolUtil.maxInt(560, 30 + (170 * buttons.length)), 280, "editors/ui/warning-popup");
spr.x = (FlxG.width - spr.bWidth) / 2; spr.x = (FlxG.width - spr.bWidth) / 2;
spr.y = (FlxG.height - spr.bHeight) / 2; spr.y = (FlxG.height - spr.bHeight) / 2;
add(spr); add(spr);
add(titleSpr = new UIText(spr.x + 25, spr.y, spr.bWidth - 50, title, 15, -1)); add(titleSpr = new UIText(spr.x + 25, spr.y, spr.bWidth - 50, title, 15, -1));
titleSpr.y = spr.y + ((30 - titleSpr.height) / 2); titleSpr.y = spr.y + ((30 - titleSpr.height) / 2);
add(messageSpr = new UIText(spr.x + 10, spr.y + 40, spr.bWidth - 20, message, 15, -1)); add(messageSpr = new UIText(spr.x + 10, spr.y + 40, spr.bWidth - 20, message, 15, -1));
var xPos = (FlxG.width - (30 + (170 * buttons.length))) / 2; var xPos = (FlxG.width - (30 + (170 * buttons.length))) / 2;
for(k=>b in buttons) { for(k=>b in buttons) {
var button = new UIButton(xPos + 20 + (170 * k), spr.y + spr.bHeight - 40, b.label, function() { var button = new UIButton(xPos + 20 + (170 * k), spr.y + spr.bHeight - 40, b.label, function() {
b.onClick(this); b.onClick(this);
close(); close();
}, 160, 30); }, 160, 30);
add(button); add(button);
} }
FlxTween.tween(camera, {alpha: 1}, 0.25, {ease: FlxEase.cubeOut}); FlxTween.tween(camera, {alpha: 1}, 0.25, {ease: FlxEase.cubeOut});
FlxTween.tween(camera, {zoom: 1}, 0.66, {ease: FlxEase.elasticOut}); FlxTween.tween(camera, {zoom: 1}, 0.66, {ease: FlxEase.elasticOut});
CoolUtil.playMenuSFX(WARNING); CoolUtil.playMenuSFX(WARNING);
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
for(e in camShaders) for(e in camShaders)
e.removeShader(blurShader); e.removeShader(blurShader);
FlxTween.cancelTweensOf(warnCam); FlxTween.cancelTweensOf(warnCam);
FlxG.cameras.remove(warnCam); FlxG.cameras.remove(warnCam);
} }
public function new(title:String, message:String, buttons:Array<WarningButton>) { public function new(title:String, message:String, buttons:Array<WarningButton>) {
super(); super();
this.title = title; this.title = title;
this.message = message; this.message = message;
this.buttons = buttons; this.buttons = buttons;
} }
} }
typedef WarningCamShader = { typedef WarningCamShader = {
var cam:FlxCamera; var cam:FlxCamera;
} }
typedef WarningButton = { typedef WarningButton = {
var label:String; var label:String;
var onClick:UIWarningSubstate->Void; var onClick:UIWarningSubstate->Void;
} }
+14 -14
View File
@@ -29,20 +29,20 @@ import openfl.filters.ShaderFilter;
import openfl.Vector; import openfl.Vector;
class HudCamera extends FlxCamera { class HudCamera extends FlxCamera {
public var downscroll:Bool = false; public var downscroll:Bool = false;
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
flipY = downscroll; flipY = downscroll;
} }
public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false,
?shader:FlxShader):Void ?shader:FlxShader):Void
{ {
if (downscroll) { if (downscroll) {
matrix.scale(1, -1); matrix.scale(1, -1);
matrix.translate(0, height); matrix.translate(0, height);
} }
super.drawPixels(frame, pixels, matrix, transform, blend, smoothing, shader); super.drawPixels(frame, pixels, matrix, transform, blend, smoothing, shader);
} }
} }
+93 -93
View File
@@ -4,112 +4,112 @@ import flixel.util.FlxSort;
import funkin.system.Conductor; import funkin.system.Conductor;
class NoteGroup extends FlxTypedGroup<Note> { class NoteGroup extends FlxTypedGroup<Note> {
var __loopSprite:Note; var __loopSprite:Note;
var i:Int = 0; var i:Int = 0;
var __currentlyLooping:Bool = false; var __currentlyLooping:Bool = false;
public function addNotes(notes:Array<Note>) { public function addNotes(notes:Array<Note>) {
for(e in notes) add(e); for(e in notes) add(e);
sortNotes(); sortNotes();
} }
public function sortNotes() { public function sortNotes() {
sort(function(i, n1, n2) { sort(function(i, n1, n2) {
if (n1.strumTime == n2.strumTime) if (n1.strumTime == n2.strumTime)
return n1.isSustainNote ? -1 : 1; return n1.isSustainNote ? -1 : 1;
return FlxSort.byValues(FlxSort.ASCENDING, n1.strumTime, n2.strumTime); return FlxSort.byValues(FlxSort.ASCENDING, n1.strumTime, n2.strumTime);
}); });
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
i = 0; i = 0;
__loopSprite = null; __loopSprite = null;
while(i < length) { while(i < length) {
__loopSprite = members[i]; __loopSprite = members[i];
if (__loopSprite == null || !__loopSprite.exists || !__loopSprite.active) { if (__loopSprite == null || !__loopSprite.exists || !__loopSprite.active) {
i++; i++;
continue; continue;
} }
if (__loopSprite.strumTime - Conductor.songPosition > 1500) if (__loopSprite.strumTime - Conductor.songPosition > 1500)
break; break;
__loopSprite.update(elapsed); __loopSprite.update(elapsed);
i++; i++;
} }
} }
public override function draw() { public override function draw() {
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras; @:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
@:privateAccess if (cameras != null) FlxCamera._defaultCameras = cameras; @:privateAccess if (cameras != null) FlxCamera._defaultCameras = cameras;
i = 0; i = 0;
__loopSprite = null; __loopSprite = null;
var oldCur = __currentlyLooping; var oldCur = __currentlyLooping;
__currentlyLooping = true; __currentlyLooping = true;
while(i < length) { while(i < length) {
__loopSprite = members[i]; __loopSprite = members[i];
if (__loopSprite == null || !__loopSprite.exists || !__loopSprite.visible) { if (__loopSprite == null || !__loopSprite.exists || !__loopSprite.visible) {
i++; i++;
continue; continue;
} }
if (__loopSprite.strumTime - Conductor.songPosition > 1500) break; if (__loopSprite.strumTime - Conductor.songPosition > 1500) break;
__loopSprite.draw(); __loopSprite.draw();
i++; i++;
} }
__currentlyLooping = oldCur; __currentlyLooping = oldCur;
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras; @:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
} }
public override function forEach(noteFunc:Note->Void, recursive:Bool = false) { public override function forEach(noteFunc:Note->Void, recursive:Bool = false) {
i = 0; i = 0;
__loopSprite = null; __loopSprite = null;
var oldCur = __currentlyLooping; var oldCur = __currentlyLooping;
__currentlyLooping = true; __currentlyLooping = true;
while(i < length) { while(i < length) {
__loopSprite = members[i]; __loopSprite = members[i];
if (__loopSprite == null || !__loopSprite.exists) { if (__loopSprite == null || !__loopSprite.exists) {
i++; i++;
continue; continue;
} }
if (__loopSprite.strumTime - Conductor.songPosition > 1500) break; if (__loopSprite.strumTime - Conductor.songPosition > 1500) break;
noteFunc(__loopSprite); noteFunc(__loopSprite);
i++; i++;
} }
__currentlyLooping = oldCur; __currentlyLooping = oldCur;
} }
public override function forEachAlive(noteFunc:Note->Void, recursive:Bool = false) { public override function forEachAlive(noteFunc:Note->Void, recursive:Bool = false) {
forEach(function(note) { forEach(function(note) {
if (note.alive) noteFunc(note); if (note.alive) noteFunc(note);
}, recursive); }, recursive);
} }
public override function remove(Object:Note, Splice:Bool = false):Note public override function remove(Object:Note, Splice:Bool = false):Note
{ {
if (members == null) if (members == null)
return null; return null;
var index:Int = members.indexOf(Object); var index:Int = members.indexOf(Object);
if (index < 0) if (index < 0)
return null; return null;
// doesnt prevent looping from breaking // doesnt prevent looping from breaking
if (Splice && __currentlyLooping && i >= index) if (Splice && __currentlyLooping && i >= index)
i--; i--;
if (Splice) if (Splice)
{ {
members.splice(index, 1); members.splice(index, 1);
length--; length--;
} }
else else
members[index] = null; members[index] = null;
if (_memberRemoved != null) if (_memberRemoved != null)
_memberRemoved.dispatch(Object); _memberRemoved.dispatch(Object);
return Object; return Object;
} }
} }
+95 -95
View File
@@ -3,114 +3,114 @@ package funkin.game;
import haxe.xml.Access; import haxe.xml.Access;
class SplashGroup extends FlxTypedGroup<FunkinSprite> { class SplashGroup extends FlxTypedGroup<FunkinSprite> {
/** /**
* Whenever the splash group has successfully loaded or not. * Whenever the splash group has successfully loaded or not.
*/ */
public var valid:Bool = true; public var valid:Bool = true;
/** /**
* XML data for the note splashes. * XML data for the note splashes.
*/ */
public var xml:Access; public var xml:Access;
/** /**
* Animation names sorted by strum IDs. * Animation names sorted by strum IDs.
* Use `getSplashAnim` to get one. * Use `getSplashAnim` to get one.
*/ */
public var animationNames:Array<Array<String>> = []; public var animationNames:Array<Array<String>> = [];
/** /**
* Creates a new Splash group * Creates a new Splash group
* @param path Path to the splash data (xml) * @param path Path to the splash data (xml)
*/ */
public function new(path) { public function new(path) {
super(); super();
try { try {
xml = new Access(Xml.parse(Assets.getText(path)).firstElement()); xml = new Access(Xml.parse(Assets.getText(path)).firstElement());
if (!xml.has.sprite) throw "The <splash> element requires a sprite attribute."; if (!xml.has.sprite) throw "The <splash> element requires a sprite attribute.";
var splashSprite = new FunkinSprite(); var splashSprite = new FunkinSprite();
splashSprite.antialiasing = true; splashSprite.antialiasing = true;
splashSprite.active = splashSprite.visible = false; splashSprite.active = splashSprite.visible = false;
splashSprite.loadSprite(Paths.image(xml.att.sprite)); splashSprite.loadSprite(Paths.image(xml.att.sprite));
/** /**
* ANIMATIONS * ANIMATIONS
*/ */
for(strum in xml.nodes.strum) { for(strum in xml.nodes.strum) {
var id:Null<Int> = Std.parseInt(strum.att.id); var id:Null<Int> = Std.parseInt(strum.att.id);
if (id != null) { if (id != null) {
animationNames[id] = []; animationNames[id] = [];
for(anim in strum.nodes.anim) { for(anim in strum.nodes.anim) {
if (!anim.has.name) continue; if (!anim.has.name) continue;
XMLUtil.addXMLAnimation(splashSprite, anim, false); XMLUtil.addXMLAnimation(splashSprite, anim, false);
animationNames[id].push(anim.att.name); animationNames[id].push(anim.att.name);
} }
} }
} }
if (animationNames.length <= 0) if (animationNames.length <= 0)
animationNames.push([]); animationNames.push([]);
for(anim in xml.nodes.anim) { for(anim in xml.nodes.anim) {
if (!anim.has.name) continue; if (!anim.has.name) continue;
XMLUtil.addXMLAnimation(splashSprite, anim, false); XMLUtil.addXMLAnimation(splashSprite, anim, false);
for(a in animationNames) { for(a in animationNames) {
if (a == null) continue; if (a == null) continue;
a.push(anim.att.name); a.push(anim.att.name);
} }
} }
/** /**
* END OF ANIMATIONS * END OF ANIMATIONS
*/ */
splashSprite.animation.finishCallback = function(name) { splashSprite.animation.finishCallback = function(name) {
splashSprite.active = splashSprite.visible = false; splashSprite.active = splashSprite.visible = false;
}; };
if (xml.has.scale) splashSprite.scale.scale(Std.parseFloat(xml.att.scale).getDefault(1)); if (xml.has.scale) splashSprite.scale.scale(Std.parseFloat(xml.att.scale).getDefault(1));
if (xml.has.alpha) splashSprite.alpha = Std.parseFloat(xml.att.alpha).getDefault(1); if (xml.has.alpha) splashSprite.alpha = Std.parseFloat(xml.att.alpha).getDefault(1);
if (xml.has.antialiasing) splashSprite.antialiasing = xml.att.antialiasing == "true"; if (xml.has.antialiasing) splashSprite.antialiasing = xml.att.antialiasing == "true";
add(splashSprite); add(splashSprite);
for (i in 0...7) { for (i in 0...7) {
// make 7 additional splashes // make 7 additional splashes
var spr = FunkinSprite.copyFrom(splashSprite); var spr = FunkinSprite.copyFrom(splashSprite);
spr.animation.finishCallback = function(name) { spr.animation.finishCallback = function(name) {
spr.active = spr.visible = false; spr.active = spr.visible = false;
}; };
add(spr); add(spr);
} }
// immediatly draw once and put image in GPU to prevent freezes // immediatly draw once and put image in GPU to prevent freezes
splashSprite.draw(); splashSprite.draw();
} catch(e) { } catch(e) {
Logs.trace('Couldn\'t parse splash data for "${path}": ${e.toString()}', ERROR); Logs.trace('Couldn\'t parse splash data for "${path}": ${e.toString()}', ERROR);
valid = false; valid = false;
} }
maxSize = 8; maxSize = 8;
} }
public function getSplashAnim(id:Int):String { public function getSplashAnim(id:Int):String {
if (animationNames.length <= 0) return null; if (animationNames.length <= 0) return null;
id %= animationNames.length; id %= animationNames.length;
if (animationNames[id] == null) return null; if (animationNames[id] == null) return null;
if (animationNames[id].length <= 0) return null; if (animationNames[id].length <= 0) return null;
return animationNames[id][FlxG.random.int(0, animationNames[id].length-1)]; return animationNames[id][FlxG.random.int(0, animationNames[id].length-1)];
} }
var __splash:FunkinSprite; var __splash:FunkinSprite;
public function showOnStrum(strum:Strum) { public function showOnStrum(strum:Strum) {
if (!valid) return null; if (!valid) return null;
__splash = recycle(); __splash = recycle();
__splash.cameras = strum.lastDrawCameras; __splash.cameras = strum.lastDrawCameras;
__splash.setPosition(strum.x + ((strum.width - __splash.width) / 2), strum.y + ((strum.height - __splash.height) / 2)); __splash.setPosition(strum.x + ((strum.width - __splash.width) / 2), strum.y + ((strum.height - __splash.height) / 2));
__splash.active = __splash.visible = true; __splash.active = __splash.visible = true;
__splash.playAnim(getSplashAnim(strum.ID), true); __splash.playAnim(getSplashAnim(strum.ID), true);
__splash.scrollFactor.set(strum.scrollFactor.x, strum.scrollFactor.y); __splash.scrollFactor.set(strum.scrollFactor.x, strum.scrollFactor.y);
return __splash; return __splash;
} }
} }
+39 -39
View File
@@ -2,49 +2,49 @@ package funkin.game;
class SplashHandler extends FlxTypedGroup<FunkinSprite> { class SplashHandler extends FlxTypedGroup<FunkinSprite> {
/** /**
* Map containing all of the splashes group. * Map containing all of the splashes group.
*/ */
public var grpMap:Map<String, SplashGroup> = []; public var grpMap:Map<String, SplashGroup> = [];
public function new() { public function new() {
super(); super();
} }
/** /**
* Returns a group of splashes, and creates it if it doesn't exist. * Returns a group of splashes, and creates it if it doesn't exist.
* @param path Path to the splashes XML (`Paths.xml('splashes/splash')`) * @param path Path to the splashes XML (`Paths.xml('splashes/splash')`)
*/ */
public function getSplashGroup(name:String) { public function getSplashGroup(name:String) {
if (!grpMap.exists(name)) { if (!grpMap.exists(name)) {
var grp = new SplashGroup(Paths.xml('splashes/$name')); var grp = new SplashGroup(Paths.xml('splashes/$name'));
grpMap.set(name, grp); grpMap.set(name, grp);
} }
return grpMap.get(name); return grpMap.get(name);
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
for(grp in grpMap) for(grp in grpMap)
grp.destroy(); grp.destroy();
grpMap = null; grpMap = null;
} }
var _firstDraw:Bool = true; var _firstDraw:Bool = true;
public override function draw() { public override function draw() {
super.draw(); super.draw();
if (_firstDraw != (_firstDraw = false)) if (_firstDraw != (_firstDraw = false))
for(grp in grpMap) for(grp in grpMap)
grp.draw(); grp.draw();
} }
var __grp:SplashGroup; var __grp:SplashGroup;
public function showSplash(name:String, strum:Strum) { public function showSplash(name:String, strum:Strum) {
__grp = getSplashGroup(name); __grp = getSplashGroup(name);
add(__grp.showOnStrum(strum)); add(__grp.showOnStrum(strum));
// max 8 rendered splashes // max 8 rendered splashes
while(members.length > 8) while(members.length > 8)
remove(members[0]); remove(members[0]);
} }
} }
+192 -192
View File
@@ -9,227 +9,227 @@ import haxe.io.Path;
using StringTools; using StringTools;
class Stage extends FlxBasic implements IBeatReceiver { class Stage extends FlxBasic implements IBeatReceiver {
public var stageXML:Access; public var stageXML:Access;
public var stagePath:String; public var stagePath:String;
public var stageSprites:Map<String, FlxSprite> = []; public var stageSprites:Map<String, FlxSprite> = [];
public var stageScript:Script; public var stageScript:Script;
public var state:FlxState; public var state:FlxState;
public var characterPoses:Map<String, StageCharPos> = []; public var characterPoses:Map<String, StageCharPos> = [];
public function getSprite(name:String) { public function getSprite(name:String) {
return stageSprites[name]; return stageSprites[name];
} }
public function new(stage:String, ?state:FlxState) { public function new(stage:String, ?state:FlxState) {
super(); super();
if (state == null) state = PlayState.instance; if (state == null) state = PlayState.instance;
if (state == null) state = FlxG.state; if (state == null) state = FlxG.state;
this.state = state; this.state = state;
stagePath = Paths.xml('stages/$stage'); stagePath = Paths.xml('stages/$stage');
try { try {
if (Assets.exists(stagePath)) stageXML = new Access(Xml.parse(Assets.getText(stagePath)).firstElement()); if (Assets.exists(stagePath)) stageXML = new Access(Xml.parse(Assets.getText(stagePath)).firstElement());
} catch(e) { } catch(e) {
Logs.trace('Couldn\'t load stage "$stage": ${e.message}', ERROR); Logs.trace('Couldn\'t load stage "$stage": ${e.message}', ERROR);
} }
if (stageXML != null) { if (stageXML != null) {
var spritesParentFolder = ""; var spritesParentFolder = "";
if (PlayState.instance != null) { if (PlayState.instance != null) {
if (stageXML.has.zoom) { if (stageXML.has.zoom) {
var parsed:Null<Float> = Std.parseFloat(stageXML.att.zoom); var parsed:Null<Float> = Std.parseFloat(stageXML.att.zoom);
if (parsed != null && PlayState.instance != null) PlayState.instance.defaultCamZoom = parsed; if (parsed != null && PlayState.instance != null) PlayState.instance.defaultCamZoom = parsed;
} }
PlayState.instance.curStage = stageXML.has.name ? stageXML.att.name : stage; PlayState.instance.curStage = stageXML.has.name ? stageXML.att.name : stage;
} }
if (stageXML.has.folder) { if (stageXML.has.folder) {
spritesParentFolder = stageXML.att.folder; spritesParentFolder = stageXML.att.folder;
if (spritesParentFolder.charAt(spritesParentFolder.length-1) != "/") spritesParentFolder = spritesParentFolder + "/"; if (spritesParentFolder.charAt(spritesParentFolder.length-1) != "/") spritesParentFolder = spritesParentFolder + "/";
} }
var elems = []; var elems = [];
for(node in stageXML.elements) { for(node in stageXML.elements) {
if (node.name == "high-memory" && !Options.lowMemoryMode) if (node.name == "high-memory" && !Options.lowMemoryMode)
for(e in node.elements) for(e in node.elements)
elems.push(e); elems.push(e);
else else
elems.push(node); elems.push(node);
} }
for(node in elems) { for(node in elems) {
var sprite:Dynamic = switch(node.name) { var sprite:Dynamic = switch(node.name) {
case "sprite" | "spr" | "sparrow": case "sprite" | "spr" | "sparrow":
if (!node.has.sprite || !node.has.name || !node.has.x || !node.has.y) continue; if (!node.has.sprite || !node.has.name || !node.has.x || !node.has.y) continue;
var spr = XMLUtil.createSpriteFromXML(node, spritesParentFolder, BEAT); var spr = XMLUtil.createSpriteFromXML(node, spritesParentFolder, BEAT);
if (!node.has.zoomfactor && PlayState.instance != null) if (!node.has.zoomfactor && PlayState.instance != null)
spr.initialZoom = PlayState.instance.defaultCamZoom; spr.initialZoom = PlayState.instance.defaultCamZoom;
stageSprites.set(spr.name, spr); stageSprites.set(spr.name, spr);
state.add(spr); state.add(spr);
spr; spr;
case "box": case "box":
if ( !node.has.name || !node.has.width || !node.has.height) continue; if ( !node.has.name || !node.has.width || !node.has.height) continue;
var spr = new FlxSprite( var spr = new FlxSprite(
(node.has.x) ? Std.parseFloat(node.att.x) : 0, (node.has.x) ? Std.parseFloat(node.att.x) : 0,
(node.has.y) ? Std.parseFloat(node.att.y) : 0 (node.has.y) ? Std.parseFloat(node.att.y) : 0
).makeGraphic( ).makeGraphic(
Std.parseInt(node.att.width), Std.parseInt(node.att.width),
Std.parseInt(node.att.height), Std.parseInt(node.att.height),
(node.has.color) ? CoolUtil.getColorFromDynamic(node.att.color) : 0xFFFFFFFF (node.has.color) ? CoolUtil.getColorFromDynamic(node.att.color) : 0xFFFFFFFF
); );
stageSprites.set(node.getAtt("name"), spr); stageSprites.set(node.getAtt("name"), spr);
state.add(spr); state.add(spr);
spr; spr;
case "boyfriend" | "bf": case "boyfriend" | "bf":
addCharPos("boyfriend", node, { addCharPos("boyfriend", node, {
x: 770, x: 770,
y: 100, y: 100,
flip: true flip: true
}); });
null; null;
case "girlfriend" | "gf": case "girlfriend" | "gf":
addCharPos("girlfriend", node, { addCharPos("girlfriend", node, {
x: 400, x: 400,
y: 130, y: 130,
flip: false flip: false
}); });
null; null;
case "dad" | "opponent": case "dad" | "opponent":
addCharPos("dad", node, { addCharPos("dad", node, {
x: 100, x: 100,
y: 100, y: 100,
flip: false flip: false
}); });
null; null;
case "character": case "character":
if (!node.has.name) continue; if (!node.has.name) continue;
addCharPos(node.att.name, node); addCharPos(node.att.name, node);
null; null;
case "ratings" | "combo": case "ratings" | "combo":
if (PlayState.instance == null) continue; if (PlayState.instance == null) continue;
PlayState.instance.comboGroup.setPosition( PlayState.instance.comboGroup.setPosition(
Std.parseFloat(node.getAtt("x")).getDefault(PlayState.instance.comboGroup.x), Std.parseFloat(node.getAtt("x")).getDefault(PlayState.instance.comboGroup.x),
Std.parseFloat(node.getAtt("y")).getDefault(PlayState.instance.comboGroup.y) Std.parseFloat(node.getAtt("y")).getDefault(PlayState.instance.comboGroup.y)
); );
PlayState.instance.add(PlayState.instance.comboGroup); PlayState.instance.add(PlayState.instance.comboGroup);
PlayState.instance.comboGroup; PlayState.instance.comboGroup;
default: null; default: null;
} }
if (sprite != null) { if (sprite != null) {
for(e in node.nodes.property) for(e in node.nodes.property)
XMLUtil.applyXMLProperty(sprite, e); XMLUtil.applyXMLProperty(sprite, e);
} }
} }
} }
if (characterPoses["girlfriend"] == null) if (characterPoses["girlfriend"] == null)
addCharPos("girlfriend", null, { addCharPos("girlfriend", null, {
x: 400, x: 400,
y: 130, y: 130,
flip: false flip: false
}); });
if (characterPoses["dad"] == null) if (characterPoses["dad"] == null)
addCharPos("dad", null, { addCharPos("dad", null, {
x: 100, x: 100,
y: 100, y: 100,
flip: false flip: false
}); });
if (characterPoses["boyfriend"] == null) if (characterPoses["boyfriend"] == null)
addCharPos("boyfriend", null, { addCharPos("boyfriend", null, {
x: 770, x: 770,
y: 100, y: 100,
flip: true flip: true
}); });
if (PlayState.instance == null) return; if (PlayState.instance == null) return;
stageScript = Script.create(Paths.script('data/stages/$stage')); stageScript = Script.create(Paths.script('data/stages/$stage'));
for(k=>e in stageSprites) { for(k=>e in stageSprites) {
stageScript.set(k, e); stageScript.set(k, e);
} }
PlayState.instance.scripts.add(stageScript); PlayState.instance.scripts.add(stageScript);
} }
public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo) { public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo) {
var dummyBasic:FlxBasic = new FlxBasic(); var dummyBasic:FlxBasic = new FlxBasic();
dummyBasic.active = false; dummyBasic.active = false;
state.add(dummyBasic); state.add(dummyBasic);
characterPoses[name] = { characterPoses[name] = {
node: node, node: node,
nonXMLInfo: nonXMLInfo, nonXMLInfo: nonXMLInfo,
dummy: dummyBasic dummy: dummyBasic
}; };
} }
public function isCharFlipped(posName:String, def:Bool = false) { public function isCharFlipped(posName:String, def:Bool = false) {
if (characterPoses[posName] != null) { if (characterPoses[posName] != null) {
var charPos = characterPoses[posName]; var charPos = characterPoses[posName];
if (charPos.node != null && charPos.node.has.flip) if (charPos.node != null && charPos.node.has.flip)
return charPos.node.att.flip == "true"; return charPos.node.att.flip == "true";
if (charPos.nonXMLInfo != null) if (charPos.nonXMLInfo != null)
return characterPoses[posName].nonXMLInfo.flip; return characterPoses[posName].nonXMLInfo.flip;
} }
return def; return def;
} }
public function applyCharStuff(char:Character, posName:String) { public function applyCharStuff(char:Character, posName:String) {
if (characterPoses[posName] == null) if (characterPoses[posName] == null)
state.add(char); state.add(char);
else { else {
var charPos = characterPoses[posName]; var charPos = characterPoses[posName];
if (charPos.nonXMLInfo != null) if (charPos.nonXMLInfo != null)
char.setPosition(charPos.nonXMLInfo.x, charPos.nonXMLInfo.y); char.setPosition(charPos.nonXMLInfo.x, charPos.nonXMLInfo.y);
if (charPos.node != null) if (charPos.node != null)
doCharNodeShit(char, charPos.node); doCharNodeShit(char, charPos.node);
state.insert(state.members.indexOf(charPos.dummy), char); state.insert(state.members.indexOf(charPos.dummy), char);
} }
} }
private static function doCharNodeShit(char:Character, node:Access) { private static function doCharNodeShit(char:Character, node:Access) {
if (node.has.x) { if (node.has.x) {
var x:Null<Float> = Std.parseFloat(node.att.x); var x:Null<Float> = Std.parseFloat(node.att.x);
if (x != null) char.x = x; if (x != null) char.x = x;
} }
if (node.has.y) { if (node.has.y) {
var y:Null<Float> = Std.parseFloat(node.att.y); var y:Null<Float> = Std.parseFloat(node.att.y);
if (y != null) char.y = y; if (y != null) char.y = y;
} }
if (node.has.camxoffset) { if (node.has.camxoffset) {
var x:Null<Float> = Std.parseFloat(node.att.camxoffset); var x:Null<Float> = Std.parseFloat(node.att.camxoffset);
if (x != null) char.cameraOffset.x += x; if (x != null) char.cameraOffset.x += x;
} }
if (node.has.camyoffset) { if (node.has.camyoffset) {
var y:Null<Float> = Std.parseFloat(node.att.camyoffset); var y:Null<Float> = Std.parseFloat(node.att.camyoffset);
if (y != null) char.cameraOffset.y += y; if (y != null) char.cameraOffset.y += y;
} }
if (node.has.scroll) { if (node.has.scroll) {
var scroll:Null<Float> = Std.parseFloat(node.att.scroll); var scroll:Null<Float> = Std.parseFloat(node.att.scroll);
if (scroll != null) char.scrollFactor.set(scroll, scroll); if (scroll != null) char.scrollFactor.set(scroll, scroll);
} }
} }
public function beatHit(curBeat:Int) {} public function beatHit(curBeat:Int) {}
public function stepHit(curStep:Int) {} public function stepHit(curStep:Int) {}
public function measureHit(curMeasure:Int) {} public function measureHit(curMeasure:Int) {}
} }
typedef StageCharPos = { typedef StageCharPos = {
var node:Access; var node:Access;
var dummy:FlxBasic; var dummy:FlxBasic;
var ?nonXMLInfo:StageCharPosInfo; var ?nonXMLInfo:StageCharPosInfo;
} }
typedef StageCharPosInfo = { typedef StageCharPosInfo = {
var x:Float; var x:Float;
var y:Float; var y:Float;
var flip:Bool; var flip:Bool;
} }
+104 -104
View File
@@ -4,122 +4,122 @@ import flixel.math.FlxPoint;
import funkin.system.Conductor; import funkin.system.Conductor;
class Strum extends FlxSprite { class Strum extends FlxSprite {
public var cpu = false; public var cpu = false;
public var lastHit:Float = -5000; public var lastHit:Float = -5000;
public var scrollSpeed:Null<Float> = null; // custom scroll speed per strum public var scrollSpeed:Null<Float> = null; // custom scroll speed per strum
public var noteAngle:Null<Float> = null; // custom scroll speed per strum public var noteAngle:Null<Float> = null; // custom scroll speed per strum
public var lastDrawCameras(default, null):Array<FlxCamera> = []; public var lastDrawCameras(default, null):Array<FlxCamera> = [];
public inline function getScrollSpeed(?note:Note):Float { public inline function getScrollSpeed(?note:Note):Float {
if (note != null && note.scrollSpeed != null) return note.scrollSpeed; if (note != null && note.scrollSpeed != null) return note.scrollSpeed;
if (scrollSpeed != null) return scrollSpeed; if (scrollSpeed != null) return scrollSpeed;
if (PlayState.instance != null) return PlayState.instance.scrollSpeed; if (PlayState.instance != null) return PlayState.instance.scrollSpeed;
return 1; return 1;
} }
public inline function getNotesAngle(?note:Note):Float { public inline function getNotesAngle(?note:Note):Float {
if (note != null && note.noteAngle != null) return note.noteAngle; if (note != null && note.noteAngle != null) return note.noteAngle;
if (noteAngle != null) return noteAngle; if (noteAngle != null) return noteAngle;
return angle; return angle;
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (cpu) { if (cpu) {
if (lastHit + (Conductor.crochet / 2) < Conductor.songPosition && getAnim() == "confirm") { if (lastHit + (Conductor.crochet / 2) < Conductor.songPosition && getAnim() == "confirm") {
playAnim("static"); playAnim("static");
} }
} }
} }
public override function draw() { public override function draw() {
lastDrawCameras = [for(c in cameras) c]; lastDrawCameras = [for(c in cameras) c];
super.draw(); super.draw();
} }
@:noCompletion public static final PIX180:Float = 565.4866776461628; // 180 * Math.PI @:noCompletion public static final PIX180:Float = 565.4866776461628; // 180 * Math.PI
@:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2; @:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2;
public function updateNotePosition(daNote:Note) { public function updateNotePosition(daNote:Note) {
if (!daNote.exists) return; if (!daNote.exists) return;
daNote.__strumCameras = lastDrawCameras; daNote.__strumCameras = lastDrawCameras;
daNote.__strum = this; daNote.__strum = this;
daNote.scrollFactor.set(scrollFactor.x, scrollFactor.y); daNote.scrollFactor.set(scrollFactor.x, scrollFactor.y);
daNote.__noteAngle = getNotesAngle(daNote); daNote.__noteAngle = getNotesAngle(daNote);
daNote.angle = daNote.isSustainNote ? daNote.__noteAngle : angle; daNote.angle = daNote.isSustainNote ? daNote.__noteAngle : angle;
if (daNote.strumRelativePos) { if (daNote.strumRelativePos) {
daNote.setPosition(daNote.isSustainNote ? ((Note.swagWidth - daNote.width) / 2) : 0, (daNote.strumTime - Conductor.songPosition) * (0.45 * FlxMath.roundDecimal(getScrollSpeed(daNote), 2))); daNote.setPosition(daNote.isSustainNote ? ((Note.swagWidth - daNote.width) / 2) : 0, (daNote.strumTime - Conductor.songPosition) * (0.45 * FlxMath.roundDecimal(getScrollSpeed(daNote), 2)));
if (daNote.isSustainNote) daNote.y += N_WIDTHDIV2; if (daNote.isSustainNote) daNote.y += N_WIDTHDIV2;
} else { } else {
var offset = FlxPoint.get(0, (Conductor.songPosition - daNote.strumTime) * (0.45 * FlxMath.roundDecimal(getScrollSpeed(daNote), 2))); var offset = FlxPoint.get(0, (Conductor.songPosition - daNote.strumTime) * (0.45 * FlxMath.roundDecimal(getScrollSpeed(daNote), 2)));
var realOffset = FlxPoint.get(0, 0); var realOffset = FlxPoint.get(0, 0);
if (daNote.isSustainNote) offset.y -= N_WIDTHDIV2; if (daNote.isSustainNote) offset.y -= N_WIDTHDIV2;
if (Std.int(daNote.__noteAngle % 360) != 0) { if (Std.int(daNote.__noteAngle % 360) != 0) {
var noteAngleCos = FlxMath.fastCos(daNote.__noteAngle / PIX180); var noteAngleCos = FlxMath.fastCos(daNote.__noteAngle / PIX180);
var noteAngleSin = FlxMath.fastSin(daNote.__noteAngle / PIX180); var noteAngleSin = FlxMath.fastSin(daNote.__noteAngle / PIX180);
var aOffset:FlxPoint = FlxPoint.get( var aOffset:FlxPoint = FlxPoint.get(
(daNote.origin.x / daNote.scale.x) - daNote.offset.x, (daNote.origin.x / daNote.scale.x) - daNote.offset.x,
(daNote.origin.y / daNote.scale.y) - daNote.offset.y (daNote.origin.y / daNote.scale.y) - daNote.offset.y
); );
realOffset.x = -aOffset.x + (noteAngleCos * (offset.x + aOffset.x)) + (noteAngleSin * (offset.y + aOffset.y)); realOffset.x = -aOffset.x + (noteAngleCos * (offset.x + aOffset.x)) + (noteAngleSin * (offset.y + aOffset.y));
realOffset.y = -aOffset.y + (noteAngleSin * (offset.x + aOffset.x)) + (noteAngleCos * (offset.y + aOffset.y)); realOffset.y = -aOffset.y + (noteAngleSin * (offset.x + aOffset.x)) + (noteAngleCos * (offset.y + aOffset.y));
aOffset.put(); aOffset.put();
} else { } else {
realOffset.x = offset.x; realOffset.x = offset.x;
realOffset.y = offset.y; realOffset.y = offset.y;
} }
realOffset.y *= -1; realOffset.y *= -1;
daNote.setPosition(x + realOffset.x, y + realOffset.y); daNote.setPosition(x + realOffset.x, y + realOffset.y);
offset.put(); offset.put();
realOffset.put(); realOffset.put();
} }
} }
public function updateSustain(daNote:Note) { public function updateSustain(daNote:Note) {
if (!daNote.isSustainNote) return; if (!daNote.isSustainNote) return;
daNote.updateSustain(this); daNote.updateSustain(this);
} }
public function updatePlayerInput(pressed:Bool, justPressed:Bool, justReleased:Bool) { public function updatePlayerInput(pressed:Bool, justPressed:Bool, justReleased:Bool) {
switch(getAnim()) { switch(getAnim()) {
case "confirm": case "confirm":
if (justReleased || !pressed) if (justReleased || !pressed)
playAnim("static"); playAnim("static");
case "pressed": case "pressed":
if (justReleased || !pressed) if (justReleased || !pressed)
playAnim("static"); playAnim("static");
case "static": case "static":
if (justPressed || pressed) if (justPressed || pressed)
playAnim("pressed"); playAnim("pressed");
case null: case null:
playAnim("static"); playAnim("static");
} }
centerOffsets(); centerOffsets();
centerOrigin(); centerOrigin();
} }
public function press(time:Float) { public function press(time:Float) {
lastHit = time; lastHit = time;
playAnim("confirm"); playAnim("confirm");
} }
public function playAnim(anim:String, force:Bool = true) { public function playAnim(anim:String, force:Bool = true) {
var oldAnim = animation.curAnim; var oldAnim = animation.curAnim;
animation.play(anim, force); animation.play(anim, force);
centerOffsets(); centerOffsets();
centerOrigin(); centerOrigin();
} }
public function getAnim() { public function getAnim() {
return animation.curAnim == null ? null : animation.curAnim.name; return animation.curAnim == null ? null : animation.curAnim.name;
} }
} }
+181 -181
View File
@@ -9,206 +9,206 @@ import funkin.system.Controls;
import flixel.tweens.FlxTween; import flixel.tweens.FlxTween;
class StrumLine extends FlxTypedGroup<Strum> { class StrumLine extends FlxTypedGroup<Strum> {
/** /**
* Signal that triggers whenever a note is hit. Similar to onPlayerHit and onDadHit, except strumline specific. * Signal that triggers whenever a note is hit. Similar to onPlayerHit and onDadHit, except strumline specific.
* To add a listener, do * To add a listener, do
* `strumLine.onHit.add(function(e:NoteHitEvent) {});` * `strumLine.onHit.add(function(e:NoteHitEvent) {});`
*/ */
public var onHit:FlxTypedSignal<NoteHitEvent->Void> = new FlxTypedSignal<NoteHitEvent->Void>(); public var onHit:FlxTypedSignal<NoteHitEvent->Void> = new FlxTypedSignal<NoteHitEvent->Void>();
/** /**
* Signal that triggers whenever a note is missed. Similar to onPlayerMiss and onDadMiss, except strumline specific. * Signal that triggers whenever a note is missed. Similar to onPlayerMiss and onDadMiss, except strumline specific.
* To add a listener, do * To add a listener, do
* `strumLine.onMiss.add(function(e:NoteHitEvent) {});` * `strumLine.onMiss.add(function(e:NoteHitEvent) {});`
*/ */
public var onMiss:FlxTypedSignal<NoteHitEvent->Void> = new FlxTypedSignal<NoteHitEvent->Void>(); public var onMiss:FlxTypedSignal<NoteHitEvent->Void> = new FlxTypedSignal<NoteHitEvent->Void>();
/** /**
* Signal that triggers whenever a note is being updated. Similar to onNoteUpdate, except strumline specific. * Signal that triggers whenever a note is being updated. Similar to onNoteUpdate, except strumline specific.
* To add a listener, do * To add a listener, do
* `strumLine.onNoteUpdate.add(function(e:NoteUpdateEvent) {});` * `strumLine.onNoteUpdate.add(function(e:NoteUpdateEvent) {});`
*/ */
public var onNoteUpdate:FlxTypedSignal<NoteUpdateEvent->Void> = new FlxTypedSignal<NoteUpdateEvent->Void>(); public var onNoteUpdate:FlxTypedSignal<NoteUpdateEvent->Void> = new FlxTypedSignal<NoteUpdateEvent->Void>();
/** /**
* Array containing all of the characters "attached" to those strums. * Array containing all of the characters "attached" to those strums.
*/ */
public var characters:Array<Character>; public var characters:Array<Character>;
/** /**
* Whenever this strumline is controlled by cpu or not. * Whenever this strumline is controlled by cpu or not.
*/ */
public var cpu(default, set):Bool = false; public var cpu(default, set):Bool = false;
/** /**
* Whenever this strumline is from the opponent side or the player side. * Whenever this strumline is from the opponent side or the player side.
*/ */
public var opponentSide:Bool = false; public var opponentSide:Bool = false;
/** /**
* Controls assigned to this strumline. * Controls assigned to this strumline.
*/ */
public var controls:Controls = null; public var controls:Controls = null;
/** /**
* Chart JSON data assigned to this StrumLine (Codename format) * Chart JSON data assigned to this StrumLine (Codename format)
*/ */
public var data:ChartStrumLine = null; public var data:ChartStrumLine = null;
/** /**
* Whenever Ghost Tapping is enabled. * Whenever Ghost Tapping is enabled.
*/ */
@:isVar public var ghostTapping(get, set):Null<Bool> = null; @:isVar public var ghostTapping(get, set):Null<Bool> = null;
/** /**
* Group of all of the notes in this strumline. Using `forEach` on this group will only loop through the first notes for performance reasons. * Group of all of the notes in this strumline. Using `forEach` on this group will only loop through the first notes for performance reasons.
*/ */
public var notes:NoteGroup; public var notes:NoteGroup;
private function get_ghostTapping() { private function get_ghostTapping() {
if (this.ghostTapping != null) return this.ghostTapping; if (this.ghostTapping != null) return this.ghostTapping;
if (PlayState.instance != null) return PlayState.instance.ghostTapping; if (PlayState.instance != null) return PlayState.instance.ghostTapping;
return false; return false;
} }
private inline function set_ghostTapping(b:Bool):Bool private inline function set_ghostTapping(b:Bool):Bool
return this.ghostTapping = b; return this.ghostTapping = b;
private var strumOffset:Float = 0.25; private var strumOffset:Float = 0.25;
public function new(characters:Array<Character>, strumOffset:Float = 0.25, cpu:Bool = false, opponentSide:Bool = true, ?controls:Controls) { public function new(characters:Array<Character>, strumOffset:Float = 0.25, cpu:Bool = false, opponentSide:Bool = true, ?controls:Controls) {
super(); super();
this.characters = characters; this.characters = characters;
this.strumOffset = strumOffset; this.strumOffset = strumOffset;
this.cpu = cpu; this.cpu = cpu;
this.opponentSide = opponentSide; this.opponentSide = opponentSide;
this.controls = controls; this.controls = controls;
this.notes = new NoteGroup(); this.notes = new NoteGroup();
} }
public function generate(strumLine:ChartStrumLine) { public function generate(strumLine:ChartStrumLine) {
if (strumLine.notes != null) for(note in strumLine.notes) { if (strumLine.notes != null) for(note in strumLine.notes) {
notes.add(new Note(this, note, false)); notes.add(new Note(this, note, false));
if (note.sLen > Conductor.stepCrochet * 0.75) { if (note.sLen > Conductor.stepCrochet * 0.75) {
var len:Float = note.sLen; var len:Float = note.sLen;
var curLen:Float = 0; var curLen:Float = 0;
while(len > 10) { while(len > 10) {
curLen = Math.min(len, Conductor.stepCrochet); curLen = Math.min(len, Conductor.stepCrochet);
notes.add(new Note(this, note, true, curLen, note.sLen - len)); notes.add(new Note(this, note, true, curLen, note.sLen - len));
len -= curLen; len -= curLen;
} }
} }
} }
notes.sortNotes(); notes.sortNotes();
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
notes.update(elapsed); notes.update(elapsed);
} }
public override function draw() { public override function draw() {
super.draw(); super.draw();
notes.cameras = cameras; notes.cameras = cameras;
notes.draw(); notes.draw();
} }
public function updateNotes() { public function updateNotes() {
notes.forEach(updateNote); notes.forEach(updateNote);
} }
var __updateNote_strum:Strum; var __updateNote_strum:Strum;
public function updateNote(daNote:Note) { public function updateNote(daNote:Note) {
for(e in members) { for(e in members) {
if (e.ID == daNote.noteData % 4) { if (e.ID == daNote.noteData % 4) {
__updateNote_strum = e; __updateNote_strum = e;
break; //ing bad break; //ing bad
} }
} }
PlayState.instance.scripts.event("onNoteUpdate", PlayState.instance.__updateNote_event.recycle(daNote, FlxG.elapsed, __updateNote_strum)); PlayState.instance.scripts.event("onNoteUpdate", PlayState.instance.__updateNote_event.recycle(daNote, FlxG.elapsed, __updateNote_strum));
onNoteUpdate.dispatch(PlayState.instance.__updateNote_event); onNoteUpdate.dispatch(PlayState.instance.__updateNote_event);
if (PlayState.instance.__updateNote_event.cancelled) return; if (PlayState.instance.__updateNote_event.cancelled) return;
if (PlayState.instance.__updateNote_event.__updateHitWindow) { if (PlayState.instance.__updateNote_event.__updateHitWindow) {
daNote.canBeHit = (daNote.strumTime > Conductor.songPosition - (PlayState.instance.hitWindow * daNote.latePressWindow) daNote.canBeHit = (daNote.strumTime > Conductor.songPosition - (PlayState.instance.hitWindow * daNote.latePressWindow)
&& daNote.strumTime < Conductor.songPosition + (PlayState.instance.hitWindow * daNote.earlyPressWindow)); && daNote.strumTime < Conductor.songPosition + (PlayState.instance.hitWindow * daNote.earlyPressWindow));
if (daNote.strumTime < Conductor.songPosition - PlayState.instance.hitWindow && !daNote.wasGoodHit) if (daNote.strumTime < Conductor.songPosition - PlayState.instance.hitWindow && !daNote.wasGoodHit)
daNote.tooLate = true; daNote.tooLate = true;
} }
if (PlayState.instance.__updateNote_event.__autoCPUHit && cpu && !daNote.wasGoodHit && daNote.strumTime < Conductor.songPosition) PlayState.instance.goodNoteHit(this, daNote); if (PlayState.instance.__updateNote_event.__autoCPUHit && cpu && !daNote.wasGoodHit && daNote.strumTime < Conductor.songPosition) PlayState.instance.goodNoteHit(this, daNote);
if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + (daNote.sustainLength) < Conductor.songPosition) { if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + (daNote.sustainLength) < Conductor.songPosition) {
deleteNote(daNote); deleteNote(daNote);
return; return;
} }
if (daNote.tooLate && !cpu) { if (daNote.tooLate && !cpu) {
PlayState.instance.noteMiss(this, daNote); PlayState.instance.noteMiss(this, daNote);
return; return;
} }
if (PlayState.instance.__updateNote_event.strum == null) return; if (PlayState.instance.__updateNote_event.strum == null) return;
if (PlayState.instance.__updateNote_event.__reposNote) PlayState.instance.__updateNote_event.strum.updateNotePosition(daNote); if (PlayState.instance.__updateNote_event.__reposNote) PlayState.instance.__updateNote_event.strum.updateNotePosition(daNote);
PlayState.instance.__updateNote_event.strum.updateSustain(daNote); PlayState.instance.__updateNote_event.strum.updateSustain(daNote);
PlayState.instance.scripts.event("onNotePostUpdate", PlayState.instance.__updateNote_event); PlayState.instance.scripts.event("onNotePostUpdate", PlayState.instance.__updateNote_event);
} }
public inline function addHealth(health:Float) public inline function addHealth(health:Float)
PlayState.instance.health += health * (opponentSide ? -1 : 1); PlayState.instance.health += health * (opponentSide ? -1 : 1);
public function generateStrums(amount:Int = 4) { public function generateStrums(amount:Int = 4) {
for (i in 0...4) for (i in 0...4)
{ {
var babyArrow:Strum = new Strum((FlxG.width * strumOffset) + (Note.swagWidth * (i - 2)), PlayState.instance.strumLine.y); var babyArrow:Strum = new Strum((FlxG.width * strumOffset) + (Note.swagWidth * (i - 2)), PlayState.instance.strumLine.y);
babyArrow.ID = i; babyArrow.ID = i;
var event = PlayState.instance.scripts.event("onStrumCreation", EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.indexOf(this), i)); var event = PlayState.instance.scripts.event("onStrumCreation", EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.indexOf(this), i));
if (!event.cancelled) { if (!event.cancelled) {
babyArrow.frames = Paths.getFrames(event.sprite); babyArrow.frames = Paths.getFrames(event.sprite);
babyArrow.animation.addByPrefix('green', 'arrowUP'); babyArrow.animation.addByPrefix('green', 'arrowUP');
babyArrow.animation.addByPrefix('blue', 'arrowDOWN'); babyArrow.animation.addByPrefix('blue', 'arrowDOWN');
babyArrow.animation.addByPrefix('purple', 'arrowLEFT'); babyArrow.animation.addByPrefix('purple', 'arrowLEFT');
babyArrow.animation.addByPrefix('red', 'arrowRIGHT'); babyArrow.animation.addByPrefix('red', 'arrowRIGHT');
babyArrow.antialiasing = true; babyArrow.antialiasing = true;
babyArrow.setGraphicSize(Std.int(babyArrow.width * 0.7)); babyArrow.setGraphicSize(Std.int(babyArrow.width * 0.7));
switch (babyArrow.ID % 4) switch (babyArrow.ID % 4)
{ {
case 0: case 0:
babyArrow.animation.addByPrefix('static', 'arrowLEFT'); babyArrow.animation.addByPrefix('static', 'arrowLEFT');
babyArrow.animation.addByPrefix('pressed', 'left press', 24, false); babyArrow.animation.addByPrefix('pressed', 'left press', 24, false);
babyArrow.animation.addByPrefix('confirm', 'left confirm', 24, false); babyArrow.animation.addByPrefix('confirm', 'left confirm', 24, false);
case 1: case 1:
babyArrow.animation.addByPrefix('static', 'arrowDOWN'); babyArrow.animation.addByPrefix('static', 'arrowDOWN');
babyArrow.animation.addByPrefix('pressed', 'down press', 24, false); babyArrow.animation.addByPrefix('pressed', 'down press', 24, false);
babyArrow.animation.addByPrefix('confirm', 'down confirm', 24, false); babyArrow.animation.addByPrefix('confirm', 'down confirm', 24, false);
case 2: case 2:
babyArrow.animation.addByPrefix('static', 'arrowUP'); babyArrow.animation.addByPrefix('static', 'arrowUP');
babyArrow.animation.addByPrefix('pressed', 'up press', 24, false); babyArrow.animation.addByPrefix('pressed', 'up press', 24, false);
babyArrow.animation.addByPrefix('confirm', 'up confirm', 24, false); babyArrow.animation.addByPrefix('confirm', 'up confirm', 24, false);
case 3: case 3:
babyArrow.animation.addByPrefix('static', 'arrowRIGHT'); babyArrow.animation.addByPrefix('static', 'arrowRIGHT');
babyArrow.animation.addByPrefix('pressed', 'right press', 24, false); babyArrow.animation.addByPrefix('pressed', 'right press', 24, false);
babyArrow.animation.addByPrefix('confirm', 'right confirm', 24, false); babyArrow.animation.addByPrefix('confirm', 'right confirm', 24, false);
} }
} }
babyArrow.cpu = cpu; babyArrow.cpu = cpu;
babyArrow.updateHitbox(); babyArrow.updateHitbox();
babyArrow.scrollFactor.set(); babyArrow.scrollFactor.set();
if (event.__doAnimation) if (event.__doAnimation)
{ {
babyArrow.y -= 10; babyArrow.y -= 10;
babyArrow.alpha = 0; babyArrow.alpha = 0;
FlxTween.tween(babyArrow, {y: babyArrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * i)}); FlxTween.tween(babyArrow, {y: babyArrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * i)});
} }
add(babyArrow); add(babyArrow);
babyArrow.playAnim('static'); babyArrow.playAnim('static');
} }
} }
/** /**
* Deletes a note from this strumline. * Deletes a note from this strumline.
@@ -224,15 +224,15 @@ class StrumLine extends FlxTypedGroup<Strum> {
} }
} }
/** /**
* SETTERS & GETTERS * SETTERS & GETTERS
*/ */
#if REGION #if REGION
private inline function set_cpu(b:Bool):Bool { private inline function set_cpu(b:Bool):Bool {
for(s in members) for(s in members)
if (s != null) if (s != null)
s.cpu = b; s.cpu = b;
return cpu = b; return cpu = b;
} }
#end #end
} }
+88 -88
View File
@@ -7,57 +7,57 @@ import haxe.Http;
// TODO: Document further and perhaps make this a Haxelib. // TODO: Document further and perhaps make this a Haxelib.
class GitHub { class GitHub {
/** /**
* Gets all the releases from a specific GitHub repository using the GitHub API. * Gets all the releases from a specific GitHub repository using the GitHub API.
* @param user * @param user
* @param repository * @param repository
* @return Releases * @return Releases
*/ */
public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array<GitHubRelease> { public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array<GitHubRelease> {
try { try {
var url = 'https://api.github.com/repos/${user}/${repository}/releases'; var url = 'https://api.github.com/repos/${user}/${repository}/releases';
var data = Json.parse(__requestOnGitHubServers(url)); var data = Json.parse(__requestOnGitHubServers(url));
if (!(data is Array)) if (!(data is Array))
throw __parseGitHubException(data); throw __parseGitHubException(data);
return data; return data;
} catch(e) { } catch(e) {
if (onError != null) if (onError != null)
onError(e); onError(e);
} }
return []; return [];
} }
public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array<GitHubContributor> { public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array<GitHubContributor> {
try { try {
var url = 'https://api.github.com/repos/${user}/${repository}/contributors'; var url = 'https://api.github.com/repos/${user}/${repository}/contributors';
var data = Json.parse(__requestOnGitHubServers(url)); var data = Json.parse(__requestOnGitHubServers(url));
if (!(data is Array)) if (!(data is Array))
throw __parseGitHubException(data); throw __parseGitHubException(data);
return data; return data;
} catch(e) { } catch(e) {
if (onError != null) if (onError != null)
onError(e); onError(e);
} }
return []; return [];
} }
/** /**
* Filters all releases gotten by `getReleases` * Filters all releases gotten by `getReleases`
* @param releases Releases * @param releases Releases
* @param keepPrereleases Whenever to keep Pre-Releases. * @param keepPrereleases Whenever to keep Pre-Releases.
* @param keepDrafts Whenever to keep Drafts. * @param keepDrafts Whenever to keep Drafts.
* @return Filtered releases. * @return Filtered releases.
*/ */
public static inline function filterReleases(releases:Array<GitHubRelease>, keepPrereleases:Bool = true, keepDrafts:Bool = false) public static inline function filterReleases(releases:Array<GitHubRelease>, keepPrereleases:Bool = true, keepDrafts:Bool = false)
return [for(release in releases) if (release != null && (!release.prerelease || (release.prerelease && keepPrereleases)) && (!release.draft || (release.draft && keepDrafts))) release]; return [for(release in releases) if (release != null && (!release.prerelease || (release.prerelease && keepPrereleases)) && (!release.draft || (release.draft && keepDrafts))) release];
public static function __requestOnGitHubServers(url:String) { public static function __requestOnGitHubServers(url:String) {
var h = new Http(url); var h = new Http(url);
h.setHeader("User-Agent", "request"); h.setHeader("User-Agent", "request");
var r = null; var r = null;
h.onData = function(d) { h.onData = function(d) {
r = d; r = d;
@@ -67,10 +67,10 @@ class GitHub {
} }
h.request(false); h.request(false);
return r; return r;
} }
public static function __requestBytesOnGitHubServers(url:String) { public static function __requestBytesOnGitHubServers(url:String) {
var h = new Http(url); var h = new Http(url);
h.setHeader("User-Agent", "request"); h.setHeader("User-Agent", "request");
var r = null; var r = null;
h.onBytes = function(d) { h.onBytes = function(d) {
r = d; r = d;
@@ -80,16 +80,16 @@ class GitHub {
} }
h.request(false); h.request(false);
return r; return r;
} }
private static function __parseGitHubException(obj:Dynamic):GitHubException { private static function __parseGitHubException(obj:Dynamic):GitHubException {
var msg:String = "(No message)"; var msg:String = "(No message)";
var url:String = "(No API url)"; var url:String = "(No API url)";
if (Reflect.hasField(obj, "message")) if (Reflect.hasField(obj, "message"))
msg = Reflect.field(obj, "message"); msg = Reflect.field(obj, "message");
if (Reflect.hasField(obj, "documentation_url")) if (Reflect.hasField(obj, "documentation_url"))
url = Reflect.field(obj, "documentation_url"); url = Reflect.field(obj, "documentation_url");
return new GitHubException(msg, url); return new GitHubException(msg, url);
} }
} }
#else #else
@@ -97,38 +97,38 @@ import haxe.Json;
import haxe.Exception; import haxe.Exception;
class GitHub { class GitHub {
/** /**
* Gets all the releases from a specific GitHub repository using the GitHub API. * Gets all the releases from a specific GitHub repository using the GitHub API.
* @param user * @param user
* @param repository * @param repository
* @return Releases * @return Releases
*/ */
public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array<GitHubRelease> { public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array<GitHubRelease> {
return []; return [];
} }
public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array<GitHubContributor> { public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array<GitHubContributor> {
return []; return [];
} }
/** /**
* Filters all releases gotten by `getReleases` * Filters all releases gotten by `getReleases`
* @param releases Releases * @param releases Releases
* @param keepPrereleases Whenever to keep Pre-Releases. * @param keepPrereleases Whenever to keep Pre-Releases.
* @param keepDrafts Whenever to keep Drafts. * @param keepDrafts Whenever to keep Drafts.
* @return Filtered releases. * @return Filtered releases.
*/ */
public static inline function filterReleases(releases:Array<GitHubRelease>, keepPrereleases:Bool = true, keepDrafts:Bool = false) public static inline function filterReleases(releases:Array<GitHubRelease>, keepPrereleases:Bool = true, keepDrafts:Bool = false)
return releases; return releases;
public static function __requestOnGitHubServers(url:String) { public static function __requestOnGitHubServers(url:String) {
return null; return null;
} }
public static function __requestBytesOnGitHubServers(url:String) { public static function __requestBytesOnGitHubServers(url:String) {
return null; return null;
} }
private static function __parseGitHubException(obj:Dynamic):GitHubException { private static function __parseGitHubException(obj:Dynamic):GitHubException {
return null; return null;
} }
} }
#end #end
+13 -13
View File
@@ -3,17 +3,17 @@ package funkin.github;
import funkin.github.GitHubUser; import funkin.github.GitHubUser;
typedef GitHubAsset = { typedef GitHubAsset = {
var url:String; var url:String;
var id:Int; var id:Int;
var node_id:String; var node_id:String;
var name:String; var name:String;
var label:String; var label:String;
var uploader:GitHubUser; var uploader:GitHubUser;
var content_type:String; var content_type:String;
var state:String; var state:String;
var size:UInt; var size:UInt;
var download_count:Int; var download_count:Int;
var created_at:String; var created_at:String;
var updated_at:String; var updated_at:String;
var browser_download_url:String; var browser_download_url:String;
} }
+19 -19
View File
@@ -1,23 +1,23 @@
package funkin.github; package funkin.github;
typedef GitHubContributor = { typedef GitHubContributor = {
var login:String; var login:String;
var id:Int; var id:Int;
var node_id:String; var node_id:String;
var avatar_url:String; var avatar_url:String;
var gravatar_id:String; var gravatar_id:String;
var url:String; var url:String;
var html_url:String; var html_url:String;
var followers_url:String; var followers_url:String;
var following_url:String; var following_url:String;
var gists_url:String; var gists_url:String;
var starred_url:String; var starred_url:String;
var subscriptions_url:String; var subscriptions_url:String;
var organizations_url:String; var organizations_url:String;
var repos_url:String; var repos_url:String;
var events_url:String; var events_url:String;
var received_events_url:String; var received_events_url:String;
var type:String; var type:String;
var site_admin:Bool; var site_admin:Bool;
var contributions:Int; var contributions:Int;
} }
+7 -7
View File
@@ -3,13 +3,13 @@ package funkin.github;
import haxe.Exception; import haxe.Exception;
class GitHubException extends Exception { class GitHubException extends Exception {
public var apiMessage:String; public var apiMessage:String;
public var documentationUrl:String; public var documentationUrl:String;
public function new(apiMessage:String, documentationUrl:String) { public function new(apiMessage:String, documentationUrl:String) {
super('[GitHubException] ${apiMessage} (Check ${documentationUrl})'); super('[GitHubException] ${apiMessage} (Check ${documentationUrl})');
this.apiMessage = apiMessage; this.apiMessage = apiMessage;
this.documentationUrl = documentationUrl; this.documentationUrl = documentationUrl;
} }
} }
+9 -9
View File
@@ -1,13 +1,13 @@
package funkin.github; package funkin.github;
typedef GitHubReactions = { typedef GitHubReactions = {
var url:String; var url:String;
var total_count:Int; var total_count:Int;
// +1 and -1 cant be added, you need to use Reflect.field // +1 and -1 cant be added, you need to use Reflect.field
var laugh:Int; var laugh:Int;
var hooray:Int; var hooray:Int;
var confused:Int; var confused:Int;
var heart:Int; var heart:Int;
var rocket:Int; var rocket:Int;
var eyes:Int; var eyes:Int;
} }
+40 -40
View File
@@ -1,62 +1,62 @@
package funkin.github; package funkin.github;
typedef GitHubRelease = { typedef GitHubRelease = {
/** /**
* Body of the GitHub request (Markdown) * Body of the GitHub request (Markdown)
*/ */
var body:String; var body:String;
/** /**
* Url of the release (GitHub API) * Url of the release (GitHub API)
*/ */
var url:String; var url:String;
/** /**
* Url for the assets JSON. Also accessible via `GitHubRelease.assets` * Url for the assets JSON. Also accessible via `GitHubRelease.assets`
*/ */
var assets_url:String; var assets_url:String;
/** /**
* Template URL for asset download link. * Template URL for asset download link.
*/ */
var upload_url:String; var upload_url:String;
/** /**
* Link to the release on the GitHub website. * Link to the release on the GitHub website.
*/ */
var html_url:String; var html_url:String;
/** /**
* ID of the release. * ID of the release.
*/ */
var id:Int; var id:Int;
/** /**
* Author of the release * Author of the release
*/ */
var author:GitHubUser; var author:GitHubUser;
var node_id:String; var node_id:String;
var tag_name:String; var tag_name:String;
var target_commitish:String; var target_commitish:String;
var name:String; var name:String;
var draft:Bool; var draft:Bool;
var prerelease:Bool; var prerelease:Bool;
var created_at:String; var created_at:String;
var published_at:String; var published_at:String;
var assets:Array<GitHubAsset>; var assets:Array<GitHubAsset>;
var tarball_url:String; var tarball_url:String;
var zipball_url:String; var zipball_url:String;
var reactions:GitHubReactions; var reactions:GitHubReactions;
} }
+96 -96
View File
@@ -2,131 +2,131 @@ package funkin.github;
typedef GitHubUser = { typedef GitHubUser = {
/** /**
* Username of the user. * Username of the user.
*/ */
var login:String; var login:String;
/** /**
* ID of the user. * ID of the user.
*/ */
var id:Int; var id:Int;
/** /**
* ID of the current node on the GitHub database. * ID of the current node on the GitHub database.
*/ */
var node_id:String; var node_id:String;
/** /**
* Link to the avatar (profile picture). * Link to the avatar (profile picture).
*/ */
var avatar_url:String; var avatar_url:String;
/** /**
* Unknown * Unknown
*/ */
var gravatar_id:String; var gravatar_id:String;
/** /**
* URL to the user on GitHub's servers. * URL to the user on GitHub's servers.
*/ */
var url:String; var url:String;
/** /**
* URL to the user on GitHub's website. * URL to the user on GitHub's website.
*/ */
var html_url:String; var html_url:String;
/** /**
* URL on GitHub's API to access this user's followers. * URL on GitHub's API to access this user's followers.
*/ */
var followers_url:String; var followers_url:String;
/** /**
* URL on GitHub's API to access the accounts this user is following. * URL on GitHub's API to access the accounts this user is following.
*/ */
var following_url:String; var following_url:String;
/** /**
* URL on GitHub's API to access this user's gists. * URL on GitHub's API to access this user's gists.
*/ */
var gists_url:String; var gists_url:String;
/** /**
* URL on GitHub's API to access this user's starred repositories. * URL on GitHub's API to access this user's starred repositories.
*/ */
var starred_url:String; var starred_url:String;
// NOT COMPLETE: MISSING repos_url, organizations_url, subscriptions_url, events_url, received_events_url. // NOT COMPLETE: MISSING repos_url, organizations_url, subscriptions_url, events_url, received_events_url.
/** /**
* Type of the user. * Type of the user.
*/ */
var type:GitHubUserType; var type:GitHubUserType;
/** /**
* Whenever the user is a GitHub administrator. * Whenever the user is a GitHub administrator.
*/ */
var site_admin:Bool; var site_admin:Bool;
/** /**
* Name of the user. * Name of the user.
*/ */
var name:String; var name:String;
/** /**
* The company this user belongs to. Can be `null`. * The company this user belongs to. Can be `null`.
*/ */
var company:String; var company:String;
var blog:String; var blog:String;
var location:String; var location:String;
var email:String; var email:String;
var hireable:Null<Bool>; var hireable:Null<Bool>;
var bio:String; var bio:String;
/** /**
* Twitter username of the user. Can be null. * Twitter username of the user. Can be null.
*/ */
var twitter_username:String; var twitter_username:String;
/** /**
* Number of public repos this user own. * Number of public repos this user own.
*/ */
var public_repos:Int; var public_repos:Int;
/** /**
* Number of public gists this user own. * Number of public gists this user own.
*/ */
var public_gists:Int; var public_gists:Int;
/** /**
* Number of followers this user have * Number of followers this user have
*/ */
var followers:Int; var followers:Int;
/** /**
* Number of accounts this user follows. * Number of accounts this user follows.
*/ */
var following:Int; var following:Int;
/** /**
* Date of creation of the account * Date of creation of the account
*/ */
var created_at:String; var created_at:String;
/** /**
* Date of last account update. * Date of last account update.
*/ */
var updated_at:String; var updated_at:String;
} }
@:enum @:enum
abstract GitHubUserType(String) { abstract GitHubUserType(String) {
var USER = "User"; var USER = "User";
var ORGANIZATION = "Organization"; var ORGANIZATION = "Organization";
} }
+3 -3
View File
@@ -1,7 +1,7 @@
package funkin.interfaces; package funkin.interfaces;
interface IBeatReceiver { interface IBeatReceiver {
public function measureHit(curMeasure:Int):Void; public function measureHit(curMeasure:Int):Void;
public function beatHit(curBeat:Int):Void; public function beatHit(curBeat:Int):Void;
public function stepHit(curStep:Int):Void; public function stepHit(curStep:Int):Void;
} }
@@ -1,5 +1,5 @@
package funkin.interfaces; package funkin.interfaces;
interface IOffsetCompatible { interface IOffsetCompatible {
public function addOffset(anim:String, x:Float = 0, y:Float = 0):Void; public function addOffset(anim:String, x:Float = 0, y:Float = 0):Void;
} }
+93 -93
View File
@@ -6,113 +6,113 @@ package funkin.macros;
* It adds the `recycle` function, which allows you to "reset" an event's values. * It adds the `recycle` function, which allows you to "reset" an event's values.
*/ */
class EventMacro { class EventMacro {
public static function build():Array<Field> { public static function build():Array<Field> {
var fields = Context.getBuildFields(); var fields = Context.getBuildFields();
var curClassRest = Context.getLocalClass(); var curClassRest = Context.getLocalClass();
if (curClassRest == null) return fields; if (curClassRest == null) return fields;
var curClass = curClassRest.get(); var curClass = curClassRest.get();
if (curClass == null || curClass.name == "CancellableEvent") return fields; if (curClass == null || curClass.name == "CancellableEvent") return fields;
// gets all fields // gets all fields
var values:Array<EventVar> = []; var values:Array<EventVar> = [];
var hiddenValues:Array<EventVar> = []; var hiddenValues:Array<EventVar> = [];
for(field in fields) { for(field in fields) {
if (field.access.contains(AStatic)) continue; if (field.access.contains(AStatic)) continue;
var hidden = false; var hidden = false;
if (field.meta != null) if (field.meta != null)
for(m in field.meta) for(m in field.meta)
if (m.name == ":dox") if (m.name == ":dox")
hidden = true; hidden = true;
if (!field.access.contains(APublic)) hidden = true; if (!field.access.contains(APublic)) hidden = true;
switch(field.kind) { switch(field.kind) {
case FVar(type, expr): case FVar(type, expr):
(hidden ? hiddenValues : values).push({ (hidden ? hiddenValues : values).push({
name: field.name, name: field.name,
type: type, type: type,
expr: expr expr: expr
}); });
default: default:
continue; continue;
} }
} }
// add recycle option // add recycle option
var func:Function = { var func:Function = {
args: [for(a in values) { args: [for(a in values) {
value: a.expr, value: a.expr,
type: a.type, type: a.type,
opt: false, opt: false,
name: a.name name: a.name
}], }],
expr: { expr: {
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EBlock([]) expr: EBlock([])
} }
}; };
var funcField:Field = { var funcField:Field = {
pos: Context.currentPos(), pos: Context.currentPos(),
name: "recycle", name: "recycle",
kind: FFun(func), kind: FFun(func),
access: [APublic] access: [APublic]
}; };
fields.push(funcField); fields.push(funcField);
var p = new Printer(); var p = new Printer();
switch(func.expr.expr) { switch(func.expr.expr) {
case EBlock(exprs): case EBlock(exprs):
// add a "set this" expr for each variable // add a "set this" expr for each variable
for(v in values) { for(v in values) {
var name = v.name; var name = v.name;
exprs.push({ exprs.push({
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EBinop(OpAssign, { expr: EBinop(OpAssign, {
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EField({ expr: EField({
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EConst(CIdent("this")) expr: EConst(CIdent("this"))
}, name) }, name)
}, { }, {
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EConst(CIdent(name)) expr: EConst(CIdent(name))
}) })
}); });
} }
// add a "set this" expr to reset each private/hidden variables // add a "set this" expr to reset each private/hidden variables
for(v in hiddenValues) { for(v in hiddenValues) {
var name = v.name; var name = v.name;
exprs.push({ exprs.push({
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EBinop(OpAssign, { expr: EBinop(OpAssign, {
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EField({ expr: EField({
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EConst(CIdent("this")) expr: EConst(CIdent("this"))
}, name) }, name)
}, v.expr) }, v.expr)
}); });
} }
exprs.push(macro return this); exprs.push(macro return this);
exprs.insert(0, macro recycleBase()); exprs.insert(0, macro recycleBase());
default: default:
// nothing // nothing
} }
return fields; return fields;
} }
} }
typedef EventVar = { typedef EventVar = {
var name:String; var name:String;
var type:ComplexType; var type:ComplexType;
var expr:Expr; var expr:Expr;
} }
#end #end
+39 -39
View File
@@ -8,47 +8,47 @@ using StringTools;
* Macro used in the options class to add getters for the SOLO keybinds. * Macro used in the options class to add getters for the SOLO keybinds.
*/ */
class OptionsMacro { class OptionsMacro {
public static function build():Array<Field> { public static function build():Array<Field> {
var fields = Context.getBuildFields(); var fields = Context.getBuildFields();
for(f in fields) { for(f in fields) {
switch(f.kind) { switch(f.kind) {
case FProp(get, set, t, e): case FProp(get, set, t, e):
if (f.name.startsWith('SOLO_') && get == "get" && set == "null") { if (f.name.startsWith('SOLO_') && get == "get" && set == "null") {
// Auto-create getters for solo (P1/P2) keybinds // Auto-create getters for solo (P1/P2) keybinds
var name = f.name.substr(5); var name = f.name.substr(5);
var getterName = 'get_SOLO_$name'; var getterName = 'get_SOLO_$name';
var ponename = 'P1_$name'; var ponename = 'P1_$name';
var ptwoname = 'P2_$name'; var ptwoname = 'P2_$name';
var newFuncExpr:Expr = macro { var newFuncExpr:Expr = macro {
var a:Array<FlxKey> = []; var a:Array<FlxKey> = [];
for(e in ${{ for(e in ${{
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EConst(CIdent(ponename)) expr: EConst(CIdent(ponename))
}}) a.push(e); }}) a.push(e);
for(e in ${{ for(e in ${{
pos: Context.currentPos(), pos: Context.currentPos(),
expr: EConst(CIdent(ptwoname)) expr: EConst(CIdent(ptwoname))
}}) a.push(e); }}) a.push(e);
return a; return a;
}; };
fields.push({ fields.push({
name: getterName, name: getterName,
kind: FFun({ kind: FFun({
expr: newFuncExpr, expr: newFuncExpr,
args: [] args: []
}), }),
pos: Context.currentPos(), pos: Context.currentPos(),
access: [APrivate, AStatic, AInline] access: [APrivate, AStatic, AInline]
}); });
} }
default: default:
// nothing // nothing
} }
} }
return fields; return fields;
} }
} }
#end #end
+36 -36
View File
@@ -9,47 +9,47 @@ import haxe.macro.Expr;
* Macros containing additional help functions to expand HScript capabilities. * Macros containing additional help functions to expand HScript capabilities.
*/ */
class ScriptsMacro { class ScriptsMacro {
public static function addAdditionalClasses() { public static function addAdditionalClasses() {
Compiler.include("flixel"); Compiler.include("flixel");
Compiler.include("away3d"); Compiler.include("away3d");
Compiler.include("flx3d"); Compiler.include("flx3d");
#if (sys && !web) #if (sys && !web)
Compiler.include("sys"); Compiler.include("sys");
#end #end
Compiler.include("DateTools"); Compiler.include("DateTools");
Compiler.include("EReg"); Compiler.include("EReg");
Compiler.include("Lambda"); Compiler.include("Lambda");
Compiler.include("StringBuf"); Compiler.include("StringBuf");
Compiler.include("haxe.crypto"); Compiler.include("haxe.crypto");
Compiler.include("haxe.display"); Compiler.include("haxe.display");
Compiler.include("haxe.exceptions"); Compiler.include("haxe.exceptions");
#if !web #if !web
Compiler.include("haxe.extern"); Compiler.include("haxe.extern");
#end #end
Compiler.include("scripting"); Compiler.include("scripting");
// FOR ABSTRACTS // FOR ABSTRACTS
Compiler.addGlobalMetadata('haxe.xml', '@:build(hscript.UsingHandler.build())'); Compiler.addGlobalMetadata('haxe.xml', '@:build(hscript.UsingHandler.build())');
} }
public static function build():Array<Field> { public static function build():Array<Field> {
var fields:Array<Field> = Context.getBuildFields(); var fields:Array<Field> = Context.getBuildFields();
for(f in fields) { for(f in fields) {
switch(f.kind) { switch(f.kind) {
case FFun(func): case FFun(func):
if (f.access == null) f.access = []; if (f.access == null) f.access = [];
if (f.access.contains(AInline)) if (f.access.contains(AInline))
f.access.remove(AInline); f.access.remove(AInline);
f.access.push(ADynamic); f.access.push(ADynamic);
default: default:
// do nothing u piece of shit // do nothing u piece of shit
} }
} }
return fields; return fields;
} }
} }
#end #end
+10 -10
View File
@@ -14,18 +14,18 @@ import haxe.macro.Compiler;
* `<haxeflag name="--macro" value="funkin.macros.StdDeprecationsRemover.init()" />` * `<haxeflag name="--macro" value="funkin.macros.StdDeprecationsRemover.init()" />`
*/ */
class StdDeprecationsRemover { class StdDeprecationsRemover {
public static function init() { public static function init() {
Compiler.addGlobalMetadata('Std', '@:build(funkin.macros.StdDeprecationsRemover.build())'); Compiler.addGlobalMetadata('Std', '@:build(funkin.macros.StdDeprecationsRemover.build())');
} }
public static function build():Array<Field> { public static function build():Array<Field> {
var fields:Array<Field> = Context.getBuildFields(); var fields:Array<Field> = Context.getBuildFields();
for(f in fields) for(f in fields)
if (f.name == "is") if (f.name == "is")
f.meta = [for(e in f.meta) if (e.name != ":deprecated") e]; f.meta = [for(e in f.meta) if (e.name != ":deprecated") e];
return fields; return fields;
} }
} }
#end #end
+30 -30
View File
@@ -6,48 +6,48 @@ import flixel.text.FlxText;
import funkin.ui.FunkinText; import funkin.ui.FunkinText;
class BetaWarningState extends MusicBeatState { class BetaWarningState extends MusicBeatState {
var titleAlphabet:Alphabet; var titleAlphabet:Alphabet;
var disclaimer:FunkinText; var disclaimer:FunkinText;
var transitioning:Bool = false; var transitioning:Bool = false;
public override function create() { public override function create() {
super.create(); super.create();
titleAlphabet = new Alphabet(0, 0, "WARNING", true); titleAlphabet = new Alphabet(0, 0, "WARNING", true);
titleAlphabet.screenCenter(X); titleAlphabet.screenCenter(X);
add(titleAlphabet); add(titleAlphabet);
disclaimer = new FunkinText(16, titleAlphabet.y + titleAlphabet.height + 10, FlxG.width - 32, "", 32); disclaimer = new FunkinText(16, titleAlphabet.y + titleAlphabet.height + 10, FlxG.width - 32, "", 32);
disclaimer.alignment = CENTER; disclaimer.alignment = CENTER;
disclaimer.applyMarkup("This engine is still in a beta state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bug, please report them to the Codename Engine GitHub.\n\nPress ENTER to continue", disclaimer.applyMarkup("This engine is still in a beta state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bug, please report them to the Codename Engine GitHub.\n\nPress ENTER to continue",
[ [
new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*") new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*")
] ]
); );
add(disclaimer); add(disclaimer);
var off = Std.int((FlxG.height - (disclaimer.y + disclaimer.height)) / 2); var off = Std.int((FlxG.height - (disclaimer.y + disclaimer.height)) / 2);
disclaimer.y += off; disclaimer.y += off;
titleAlphabet.y += off; titleAlphabet.y += off;
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (controls.ACCEPT && transitioning) { if (controls.ACCEPT && transitioning) {
FlxG.camera.stopFX(); FlxG.camera.visible = false; FlxG.camera.stopFX(); FlxG.camera.visible = false;
goToTitle(); goToTitle();
} }
if (controls.ACCEPT && !transitioning) { if (controls.ACCEPT && !transitioning) {
transitioning = true; transitioning = true;
CoolUtil.playMenuSFX(CONFIRM); CoolUtil.playMenuSFX(CONFIRM);
FlxG.camera.flash(FlxColor.WHITE, 1, function() { FlxG.camera.flash(FlxColor.WHITE, 1, function() {
FlxG.camera.fade(FlxColor.BLACK, 2.5, false, goToTitle); FlxG.camera.fade(FlxColor.BLACK, 2.5, false, goToTitle);
}); });
} }
} }
private function goToTitle() { private function goToTitle() {
FlxTransitionableState.skipNextTransIn = FlxTransitionableState.skipNextTransOut = true; FlxTransitionableState.skipNextTransIn = FlxTransitionableState.skipNextTransOut = true;
+7 -7
View File
@@ -348,7 +348,7 @@ class FreeplayState extends MusicBeatState
if (event.cancelled) return; if (event.cancelled) return;
curSelected = event.value; curSelected = event.value;
if (event.playMenuSFX) CoolUtil.playMenuSFX(SCROLL, 0.7); if (event.playMenuSFX) CoolUtil.playMenuSFX(SCROLL, 0.7);
changeDiff(0, true); changeDiff(0, true);
@@ -382,9 +382,9 @@ class FreeplayState extends MusicBeatState
} }
class FreeplaySonglist { class FreeplaySonglist {
public var songs:Array<ChartMetaData> = []; public var songs:Array<ChartMetaData> = [];
public function new() {} public function new() {}
public function getSongsFromSource(source:funkin.system.AssetsLibraryList.AssetSource, useTxt:Bool = true) { public function getSongsFromSource(source:funkin.system.AssetsLibraryList.AssetSource, useTxt:Bool = true) {
var path:String = Paths.txt('freeplaySonglist'); var path:String = Paths.txt('freeplaySonglist');
@@ -403,12 +403,12 @@ class FreeplaySonglist {
return true; return true;
} }
public static function get(useTxt:Bool = true) { public static function get(useTxt:Bool = true) {
var songList = new FreeplaySonglist(); var songList = new FreeplaySonglist();
if (songList.getSongsFromSource(MODS, useTxt)) if (songList.getSongsFromSource(MODS, useTxt))
songList.getSongsFromSource(SOURCE, useTxt); songList.getSongsFromSource(SOURCE, useTxt);
return songList; return songList;
} }
} }
+54 -54
View File
@@ -7,72 +7,72 @@ import sys.FileSystem;
import flixel.tweens.FlxTween; import flixel.tweens.FlxTween;
class ModSwitchMenu extends MusicBeatSubstate { class ModSwitchMenu extends MusicBeatSubstate {
var mods:Array<String> = []; var mods:Array<String> = [];
var alphabets:FlxTypedGroup<Alphabet>; var alphabets:FlxTypedGroup<Alphabet>;
var curSelected:Int = 0; var curSelected:Int = 0;
public override function create() { public override function create() {
super.create(); super.create();
var bg = new FlxSprite(0, 0).makeGraphic(1, 1, 0xFF000000); var bg = new FlxSprite(0, 0).makeGraphic(1, 1, 0xFF000000);
bg.scale.set(FlxG.width, FlxG.height); bg.scale.set(FlxG.width, FlxG.height);
bg.updateHitbox(); bg.updateHitbox();
bg.scrollFactor.set(); bg.scrollFactor.set();
add(bg); add(bg);
bg.alpha = 0; bg.alpha = 0;
FlxTween.tween(bg, {alpha: 0.5}, 0.25, {ease: FlxEase.cubeOut}); FlxTween.tween(bg, {alpha: 0.5}, 0.25, {ease: FlxEase.cubeOut});
for(modFolder in FileSystem.readDirectory(ModsFolder.modsPath)) { for(modFolder in FileSystem.readDirectory(ModsFolder.modsPath)) {
if (FileSystem.isDirectory('${ModsFolder.modsPath}${modFolder}')) { if (FileSystem.isDirectory('${ModsFolder.modsPath}${modFolder}')) {
mods.push(modFolder); mods.push(modFolder);
} else { } else {
var ext = Path.extension(modFolder).toLowerCase(); var ext = Path.extension(modFolder).toLowerCase();
switch(ext) { switch(ext) {
case 'zip': case 'zip':
// is a zip mod!! // is a zip mod!!
mods.push(Path.withoutExtension(modFolder)); mods.push(Path.withoutExtension(modFolder));
} }
} }
} }
alphabets = new FlxTypedGroup<Alphabet>(); alphabets = new FlxTypedGroup<Alphabet>();
for(mod in mods) { for(mod in mods) {
var a = new Alphabet(0, 0, mod, true); var a = new Alphabet(0, 0, mod, true);
a.isMenuItem = true; a.isMenuItem = true;
a.scrollFactor.set(); a.scrollFactor.set();
alphabets.add(a); alphabets.add(a);
} }
add(alphabets); add(alphabets);
changeSelection(0, true); changeSelection(0, true);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); 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));
if (controls.ACCEPT) { if (controls.ACCEPT) {
ModsFolder.switchMod(mods[curSelected]); ModsFolder.switchMod(mods[curSelected]);
close(); close();
} }
if (controls.BACK) if (controls.BACK)
close(); close();
} }
public function changeSelection(change:Int, force:Bool = false) { public function changeSelection(change:Int, force:Bool = false) {
if (change == 0 && !force) return; if (change == 0 && !force) return;
curSelected = FlxMath.wrap(curSelected + change, 0, alphabets.length-1); curSelected = FlxMath.wrap(curSelected + change, 0, alphabets.length-1);
CoolUtil.playMenuSFX(SCROLL, 0.7); CoolUtil.playMenuSFX(SCROLL, 0.7);
for(k=>alphabet in alphabets.members) { for(k=>alphabet in alphabets.members) {
alphabet.alpha = 0.6; alphabet.alpha = 0.6;
alphabet.targetY = k - curSelected; alphabet.targetY = k - curSelected;
} }
alphabets.members[curSelected].alpha = 1; alphabets.members[curSelected].alpha = 1;
} }
} }
#end #end
+1 -1
View File
@@ -41,7 +41,7 @@ class PauseSubState extends MusicBeatSubstate
pauseScript = Script.create(Paths.script(script)); pauseScript = Script.create(Paths.script(script));
pauseScript.setParent(this); pauseScript.setParent(this);
pauseScript.load(); pauseScript.load();
var event = EventManager.get(PauseCreationEvent).recycle('breakfast', menuItems); var event = EventManager.get(PauseCreationEvent).recycle('breakfast', menuItems);
pauseScript.call('create', [event]); pauseScript.call('create', [event]);
+1 -1
View File
@@ -323,7 +323,7 @@ class TitleState extends MusicBeatState
} }
} }
} catch(e) { } catch(e) {
Logs.trace('Failed to load titlescreen XML: $e', ERROR); Logs.trace('Failed to load titlescreen XML: $e', ERROR);
} }
} }
#end #end
+96 -96
View File
@@ -15,120 +15,120 @@ import funkin.menus.MainMenuState;
using funkin.utils.BitmapUtil; using funkin.utils.BitmapUtil;
class CreditsCodename extends OptionsScreen { class CreditsCodename extends OptionsScreen {
public var contributorsSprites:Array<FlxSprite> = []; public var contributorsSprites:Array<FlxSprite> = [];
public var contributorsAvatars:Array<FlxGraphic> = []; public var contributorsAvatars:Array<FlxGraphic> = [];
public var contributorsColors:Array<FlxColor> = []; public var contributorsColors:Array<FlxColor> = [];
public var avatarLoadListId:Int = 0; public var avatarLoadListId:Int = 0;
public var contributors:Array<GitHubContributor>; public var contributors:Array<GitHubContributor>;
public var interpColor:FlxInterpolateColor; public var interpColor:FlxInterpolateColor;
public var errorMessage:String = ""; public var errorMessage:String = "";
public override function create() { public override function create() {
contributors = GitHub.getContributors("YoshiCrafter29", "CodenameEngine", function(e) { contributors = GitHub.getContributors("YoshiCrafter29", "CodenameEngine", function(e) {
errorMessage = Std.string(e); errorMessage = Std.string(e);
}); });
var totalContributions = 0; var totalContributions = 0;
for(c in contributors) for(c in contributors)
totalContributions += c.contributions; totalContributions += c.contributions;
options = [for(c in contributors) new TextOption( options = [for(c in contributors) new TextOption(
c.login, c.login,
'Total Contributions: ${c.contributions} / ${totalContributions} (${FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)}%) - Select to open GitHub account', 'Total Contributions: ${c.contributions} / ${totalContributions} (${FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)}%) - Select to open GitHub account',
function() { function() {
// open the link // open the link
CoolUtil.openURL(c.html_url); CoolUtil.openURL(c.html_url);
})]; })];
super.create(); super.create();
interpColor = new FlxInterpolateColor(bg.color); interpColor = new FlxInterpolateColor(bg.color);
} }
public override function changeSelection(change:Int) { public override function changeSelection(change:Int) {
if (contributors.length <= 0) if (contributors.length <= 0)
return; return;
super.changeSelection(change); super.changeSelection(change);
} }
public override function createAdditional() { public override function createAdditional() {
if (contributors.length <= 0) { if (contributors.length <= 0) {
var t = new FunkinText(0, 0, FlxG.width, 'Could not load engine contributors.\nMake sure you\'re connected to the Internet.\n\n${errorMessage}\n\nPress BACK to go back.', 40, true); var t = new FunkinText(0, 0, FlxG.width, 'Could not load engine contributors.\nMake sure you\'re connected to the Internet.\n\n${errorMessage}\n\nPress BACK to go back.', 40, true);
t.alignment = CENTER; t.alignment = CENTER;
t.borderSize *= 1.75; t.borderSize *= 1.75;
t.screenCenter(); t.screenCenter();
var bg = new FlxSprite(0, 0).makeGraphic(1, 1, 0xFF000000); var bg = new FlxSprite(0, 0).makeGraphic(1, 1, 0xFF000000);
bg.alpha = 0.5; bg.alpha = 0.5;
bg.scale.set(FlxG.width - 80, t.height + 40); bg.scale.set(FlxG.width - 80, t.height + 40);
bg.updateHitbox(); bg.updateHitbox();
bg.screenCenter(); bg.screenCenter();
add(bg); add(bg);
add(t); add(t);
return; return;
} }
for(k=>c in contributors) { for(k=>c in contributors) {
var spr = new FlxSprite(0, (OptionsScreen.optionHeight * (k+0.5)) - 48); var spr = new FlxSprite(0, (OptionsScreen.optionHeight * (k+0.5)) - 48);
spr.antialiasing = true; spr.antialiasing = true;
spr.setUnstretchedGraphicSize(96, 96, false); spr.setUnstretchedGraphicSize(96, 96, false);
spr.updateHitbox(); spr.updateHitbox();
spr.shader = new CustomShader('engine/circleProfilePicture'); spr.shader = new CustomShader('engine/circleProfilePicture');
contributorsSprites.push(spr); contributorsSprites.push(spr);
add(spr); add(spr);
} }
// asynchronous pfp loading // asynchronous pfp loading
Main.execAsync(function() { Main.execAsync(function() {
for(k=>c in contributors) { for(k=>c in contributors) {
var bytes = GitHub.__requestBytesOnGitHubServers('${c.avatar_url}&size=96'); var bytes = GitHub.__requestBytesOnGitHubServers('${c.avatar_url}&size=96');
var bmap = BitmapData.fromBytes(bytes); var bmap = BitmapData.fromBytes(bytes);
var color = bmap.getMostPresentSaturatedColor(); var color = bmap.getMostPresentSaturatedColor();
contributorsAvatars.push(FlxG.bitmap.add(bmap, false, 'GITHUB-USER:${c.login}')); contributorsAvatars.push(FlxG.bitmap.add(bmap, false, 'GITHUB-USER:${c.login}'));
contributorsColors.push(color); contributorsColors.push(color);
if (destroyed) return; if (destroyed) return;
} }
}); });
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (contributors.length <= 0) { if (contributors.length <= 0) {
if (controls.BACK) if (controls.BACK)
exit(); exit();
return; return;
} }
if (avatarLoadListId < contributorsAvatars.length) { if (avatarLoadListId < contributorsAvatars.length) {
for(i in avatarLoadListId...contributorsAvatars.length) { for(i in avatarLoadListId...contributorsAvatars.length) {
var v = contributorsSprites[i]; var v = contributorsSprites[i];
v.loadGraphic(contributorsAvatars[i]); v.loadGraphic(contributorsAvatars[i]);
v.setUnstretchedGraphicSize(96, 96, false); v.setUnstretchedGraphicSize(96, 96, false);
v.updateHitbox(); v.updateHitbox();
} }
avatarLoadListId = contributorsAvatars.length; avatarLoadListId = contributorsAvatars.length;
} }
for(k=>spr in contributorsSprites) { for(k=>spr in contributorsSprites) {
var alpha = options[k]; var alpha = options[k];
spr.x = alpha.x - 10; spr.x = alpha.x - 10;
} }
interpColor.fpsLerpTo(contributorsColors[curSelected], 0.0625); interpColor.fpsLerpTo(contributorsColors[curSelected], 0.0625);
bg.color = interpColor.color; bg.color = interpColor.color;
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
} }
public override function exit() { public override function exit() {
FlxTransitionableState.skipNextTransOut = true; FlxTransitionableState.skipNextTransOut = true;
FlxG.switchState(new CreditsMain()); FlxG.switchState(new CreditsMain());
} }
} }
+16 -16
View File
@@ -5,21 +5,21 @@ import funkin.options.OptionsScreen;
import funkin.options.type.*; import funkin.options.type.*;
class CreditsMain extends OptionsScreen { class CreditsMain extends OptionsScreen {
public override function create() { public override function create() {
options = [ options = [
// TODO: Custom Credits // TODO: Custom Credits
new TextOption("Codename Engine", "Select this to see all of the contributors of the engine!", function() { new TextOption("Codename Engine", "Select this to see all of the contributors of the engine!", function() {
FlxTransitionableState.skipNextTransIn = FlxTransitionableState.skipNextTransOut = true; FlxTransitionableState.skipNextTransIn = FlxTransitionableState.skipNextTransOut = true;
FlxG.switchState(new CreditsCodename()); FlxG.switchState(new CreditsCodename());
}), }),
new TextOption("Friday Night Funkin'", "Select this to open the itch.io page of the original game to donate!", function() { new TextOption("Friday Night Funkin'", "Select this to open the itch.io page of the original game to donate!", function() {
CoolUtil.openURL("https://ninja-muffin24.itch.io/funkin"); CoolUtil.openURL("https://ninja-muffin24.itch.io/funkin");
}) })
]; ];
super.create(); super.create();
} }
public override function exit() { public override function exit() {
FlxG.switchState(new MainMenuState()); FlxG.switchState(new MainMenuState());
} }
} }
+26 -26
View File
@@ -6,34 +6,34 @@ import lime.utils.AssetLibrary;
* Used to prevent crashes * Used to prevent crashes
*/ */
class ModdableAssetsFolder extends ModsFolderLibrary { class ModdableAssetsFolder extends ModsFolderLibrary {
public var oldLibrary:AssetLibrary; public var oldLibrary:AssetLibrary;
public override function exists(id:String, type:String) { public override function exists(id:String, type:String) {
if (!id.startsWith("assets/") && !exists('assets/$id', type)) if (!id.startsWith("assets/") && !exists('assets/$id', type))
return oldLibrary.exists(id, type); return oldLibrary.exists(id, type);
return super.exists(id, type); return super.exists(id, type);
} }
public override function getAsset(id:String, type:String) { public override function getAsset(id:String, type:String) {
if (!id.startsWith("assets/")) { if (!id.startsWith("assets/")) {
var possibleReplacement = getAsset('assets/$id', type); var possibleReplacement = getAsset('assets/$id', type);
if (possibleReplacement != null) if (possibleReplacement != null)
return possibleReplacement; return possibleReplacement;
return oldLibrary.getAsset(id, type); return oldLibrary.getAsset(id, type);
} }
return super.getAsset(id, type); return super.getAsset(id, type);
} }
public function new(folder:String, libName:String, oldLib:AssetLibrary) { public function new(folder:String, libName:String, oldLib:AssetLibrary) {
super(folder, libName); super(folder, libName);
oldLibrary = oldLib; oldLibrary = oldLib;
trace(Type.getClassName(Type.getClass(oldLibrary))); trace(Type.getClassName(Type.getClass(oldLibrary)));
} }
private override function __parseAsset(asset:String):Bool { private override function __parseAsset(asset:String):Bool {
var prefix = 'assets/'; var prefix = 'assets/';
if (!asset.startsWith(prefix)) return false; if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length); _parsedAsset = asset.substr(prefix.length);
return true; return true;
} }
} }
+12 -12
View File
@@ -22,20 +22,20 @@ import sys.FileSystem;
using StringTools; using StringTools;
interface ModsAssetLibrary { interface ModsAssetLibrary {
public var prefix:String; public var prefix:String;
public var libName:String; public var libName:String;
#if MOD_SUPPORT #if MOD_SUPPORT
public var _parsedAsset:String; public var _parsedAsset:String;
private function getAssetPath():String; private function getAssetPath():String;
private function __isCacheValid(cache:Map<String, Dynamic>, asset:String, isLocal:Bool = false):Bool; private function __isCacheValid(cache:Map<String, Dynamic>, asset:String, isLocal:Bool = false):Bool;
private function __parseAsset(asset:String):Bool; private function __parseAsset(asset:String):Bool;
public function getFiles(folder:String):Array<String>; public function getFiles(folder:String):Array<String>;
public function getFolders(folder:String):Array<String>; public function getFolders(folder:String):Array<String>;
#end #end
} }
+98 -98
View File
@@ -19,115 +19,115 @@ import haxe.io.Path;
using StringTools; using StringTools;
class ModsFolder { class ModsFolder {
/** /**
* INTERNAL - Only use when editing source mods!! * INTERNAL - Only use when editing source mods!!
*/ */
@:dox(hide) public static var onModSwitch:FlxTypedSignal<String->Void> = new FlxTypedSignal<String->Void>(); @:dox(hide) public static var onModSwitch:FlxTypedSignal<String->Void> = new FlxTypedSignal<String->Void>();
/** /**
* Current mod folder. Will affect `Paths`. * Current mod folder. Will affect `Paths`.
*/ */
public static var currentModFolder:String = null; public static var currentModFolder:String = null;
/** /**
* Map all loaded mods' folder libraries. * Map all loaded mods' folder libraries.
*/ */
public static var loadedMods:Map<String, lime.utils.AssetLibrary> = []; public static var loadedMods:Map<String, lime.utils.AssetLibrary> = [];
/** /**
* Path to the `mods` folder. * Path to the `mods` folder.
*/ */
public static var modsPath:String = "./mods/"; public static var modsPath:String = "./mods/";
/** /**
* Initialises `mods` folder by adding callbacks and such. * Initialises `mods` folder by adding callbacks and such.
*/ */
public static function init() { public static function init() {
} }
/** /**
* Loads a mod with the specified name. * Loads a mod with the specified name.
* @param modName Name of the mod * @param modName Name of the mod
* @param force Whenever the mod should be reloaded if it has already been loaded * @param force Whenever the mod should be reloaded if it has already been loaded
*/ */
public static function loadMod(mod:String, force:Bool = false) { public static function loadMod(mod:String, force:Bool = false) {
#if MOD_SUPPORT #if MOD_SUPPORT
if (mod == null) return null; // may be loading base game if (mod == null) return null; // may be loading base game
if (FileSystem.exists('${modsPath}$mod.zip')) if (FileSystem.exists('${modsPath}$mod.zip'))
return loadedMods[mod] = loadLibraryFromZip('mods/$mod'.toLowerCase(), '${modsPath}$mod.zip', force); return loadedMods[mod] = loadLibraryFromZip('mods/$mod'.toLowerCase(), '${modsPath}$mod.zip', force);
else else
return loadedMods[mod] = loadLibraryFromFolder('mods/$mod'.toLowerCase(), '${modsPath}$mod', force); return loadedMods[mod] = loadLibraryFromFolder('mods/$mod'.toLowerCase(), '${modsPath}$mod', force);
#else #else
return null; return null;
#end #end
} }
/** /**
* Switches mod - unloads all the other mods, then load this one. * Switches mod - unloads all the other mods, then load this one.
* @param libName * @param libName
*/ */
public static function switchMod(mod:String) { public static function switchMod(mod:String) {
unloadMod(ModsFolder.currentModFolder); unloadMod(ModsFolder.currentModFolder);
Options.lastLoadedMod = ModsFolder.currentModFolder = mod; Options.lastLoadedMod = ModsFolder.currentModFolder = mod;
Options.save(); Options.save();
if (ModsFolder.currentModFolder == null) return; if (ModsFolder.currentModFolder == null) return;
Paths.assetsTree.addLibrary(loadMod(ModsFolder.currentModFolder)); Paths.assetsTree.addLibrary(loadMod(ModsFolder.currentModFolder));
Main.refreshAssets(); Main.refreshAssets();
onModSwitch.dispatch(ModsFolder.currentModFolder); onModSwitch.dispatch(ModsFolder.currentModFolder);
if (FlxG.sound.music != null && FlxG.sound.music.playing) if (FlxG.sound.music != null && FlxG.sound.music.playing)
FlxG.sound.music.fadeOut(0.25, 0, function(t) { FlxG.sound.music.fadeOut(0.25, 0, function(t) {
FlxG.sound.music.stop(); FlxG.sound.music.stop();
}); });
DiscordUtil.reloadJsonData(); DiscordUtil.reloadJsonData();
TitleState.initialized = false; TitleState.initialized = false;
FlxG.switchState(new TitleState()); FlxG.switchState(new TitleState());
} }
public static function unloadMod(mod:String) { public static function unloadMod(mod:String) {
if (mod == null) return; if (mod == null) return;
Paths.assetsTree.clearCache(); Paths.assetsTree.clearCache();
FlxG.bitmap.reset(); FlxG.bitmap.reset();
Paths.assetsTree.removeLibrary(loadedMods[mod]); Paths.assetsTree.removeLibrary(loadedMods[mod]);
Assets.unloadLibrary('mods/$mod'.toLowerCase()); Assets.unloadLibrary('mods/$mod'.toLowerCase());
loadedMods[mod] = null; loadedMods[mod] = null;
} }
public static function prepareLibrary(libName:String, force:Bool = false) { public static function prepareLibrary(libName:String, force:Bool = false) {
if (Assets.hasLibrary(libName)) { if (Assets.hasLibrary(libName)) {
if (force) if (force)
Assets.unloadLibrary(libName); Assets.unloadLibrary(libName);
else else
return null; return null;
} }
var assets:AssetManifest = new AssetManifest(); var assets:AssetManifest = new AssetManifest();
assets.name = libName; assets.name = libName;
assets.version = 2; assets.version = 2;
assets.libraryArgs = []; assets.libraryArgs = [];
assets.assets = []; assets.assets = [];
return AssetLibrary.fromManifest(assets); return AssetLibrary.fromManifest(assets);
} }
public static function prepareModLibrary(libName:String, lib:ModsAssetLibrary, force:Bool = false) { public static function prepareModLibrary(libName:String, lib:ModsAssetLibrary, force:Bool = false) {
var openLib = prepareLibrary(libName, force); var openLib = prepareLibrary(libName, force);
lib.prefix = 'assets/'; lib.prefix = 'assets/';
@:privateAccess @:privateAccess
openLib.__proxy = cast(lib, lime.utils.AssetLibrary); openLib.__proxy = cast(lib, lime.utils.AssetLibrary);
Assets.registerLibrary(libName, openLib); Assets.registerLibrary(libName, openLib);
return openLib; return openLib;
} }
public static function loadLibraryFromFolder(libName:String, folder:String, force:Bool = false) { public static function loadLibraryFromFolder(libName:String, folder:String, force:Bool = false) {
return prepareModLibrary(libName, new ModsFolderLibrary(folder, libName), force); return prepareModLibrary(libName, new ModsFolderLibrary(folder, libName), force);
} }
public static function loadLibraryFromZip(libName:String, zipPath:String, force:Bool = false) { public static function loadLibraryFromZip(libName:String, zipPath:String, force:Bool = false) {
return prepareModLibrary(libName, new ZipFolderLibrary(zipPath, libName), force); return prepareModLibrary(libName, new ZipFolderLibrary(zipPath, libName), force);
} }
} }
+78 -78
View File
@@ -16,27 +16,27 @@ import sys.FileSystem;
using StringTools; using StringTools;
class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary { class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
public var folderPath:String; public var folderPath:String;
public var libName:String; public var libName:String;
public var useImageCache:Bool = true; public var useImageCache:Bool = true;
public var prefix = 'assets/'; public var prefix = 'assets/';
public function new(folderPath:String, libName:String) { public function new(folderPath:String, libName:String) {
this.folderPath = folderPath; this.folderPath = folderPath;
this.libName = libName; this.libName = libName;
this.prefix = 'assets/$libName/'; this.prefix = 'assets/$libName/';
super(); super();
} }
#if MOD_SUPPORT #if MOD_SUPPORT
private var editedTimes:Map<String, Float> = []; private var editedTimes:Map<String, Float> = [];
public var _parsedAsset:String = null; public var _parsedAsset:String = null;
public function getEditedTime(asset:String):Null<Float> { public function getEditedTime(asset:String):Null<Float> {
return editedTimes[asset]; return editedTimes[asset];
} }
public override function getAudioBuffer(id:String):AudioBuffer { public override function getAudioBuffer(id:String):AudioBuffer {
if (!exists(id, "SOUND")) if (!exists(id, "SOUND"))
return null; return null;
var path = getAssetPath(); var path = getAssetPath();
@@ -44,9 +44,9 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
var e = AudioBuffer.fromFile(path); var e = AudioBuffer.fromFile(path);
// LimeAssets.cache.audio.set('$libName:$id', e); // LimeAssets.cache.audio.set('$libName:$id', e);
return e; return e;
} }
public override function getBytes(id:String):Bytes { public override function getBytes(id:String):Bytes {
if (!exists(id, "BINARY")) if (!exists(id, "BINARY"))
return null; return null;
var path = getAssetPath(); var path = getAssetPath();
@@ -54,18 +54,18 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
var e = Bytes.fromFile(path); var e = Bytes.fromFile(path);
cachedBytes.set(id, e); cachedBytes.set(id, e);
return e; return e;
} }
public override function getFont(id:String):Font { public override function getFont(id:String):Font {
if (!exists(id, "FONT")) if (!exists(id, "FONT"))
return null; return null;
var path = getAssetPath(); var path = getAssetPath();
editedTimes[id] = FileSystem.stat(path).mtime.getTime(); editedTimes[id] = FileSystem.stat(path).mtime.getTime();
var e = Font.fromFile(path); var e = Font.fromFile(path);
return e; return e;
} }
public override function getImage(id:String):Image { public override function getImage(id:String):Image {
if (!exists(id, "IMAGE")) if (!exists(id, "IMAGE"))
return null; return null;
var path = getAssetPath(); var path = getAssetPath();
@@ -73,69 +73,69 @@ class ModsFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
var e = Image.fromFile(path); var e = Image.fromFile(path);
return e; return e;
} }
public override function getPath(id:String):String { public override function getPath(id:String):String {
if (!__parseAsset(id)) return null; if (!__parseAsset(id)) return null;
return getAssetPath(); return getAssetPath();
} }
public inline function getFolders(folder:String):Array<String> public inline function getFolders(folder:String):Array<String>
return __getFiles(folder, true); return __getFiles(folder, true);
public inline function getFiles(folder:String):Array<String> public inline function getFiles(folder:String):Array<String>
return __getFiles(folder, false); return __getFiles(folder, false);
public function __getFiles(folder:String, folders:Bool = false) { public function __getFiles(folder:String, folders:Bool = false) {
if (!folder.endsWith("/")) folder = folder + "/"; if (!folder.endsWith("/")) folder = folder + "/";
if (!__parseAsset(folder)) return []; if (!__parseAsset(folder)) return [];
var path = getAssetPath(); var path = getAssetPath();
try { try {
var result:Array<String> = []; var result:Array<String> = [];
for(e in FileSystem.readDirectory(path)) for(e in FileSystem.readDirectory(path))
if (FileSystem.isDirectory('$path$e') == folders) if (FileSystem.isDirectory('$path$e') == folders)
result.push(e); result.push(e);
return result; return result;
} catch(e) { } catch(e) {
// woops!! // woops!!
} }
return []; return [];
} }
public override function exists(asset:String, type:String):Bool { public override function exists(asset:String, type:String):Bool {
if(!__parseAsset(asset)) return false; if(!__parseAsset(asset)) return false;
return FileSystem.exists(getAssetPath()); return FileSystem.exists(getAssetPath());
} }
private function getAssetPath() { private function getAssetPath() {
return '$folderPath/$_parsedAsset'; return '$folderPath/$_parsedAsset';
} }
private function __isCacheValid(cache:Map<String, Dynamic>, asset:String, isLocalCache:Bool = false) { private function __isCacheValid(cache:Map<String, Dynamic>, asset:String, isLocalCache:Bool = false) {
if (!editedTimes.exists(asset)) if (!editedTimes.exists(asset))
return false; return false;
if (editedTimes[asset] == null || editedTimes[asset] < FileSystem.stat(getPath(asset)).mtime.getTime()) { if (editedTimes[asset] == null || editedTimes[asset] < FileSystem.stat(getPath(asset)).mtime.getTime()) {
// destroy already existing to prevent memory leak!!! // destroy already existing to prevent memory leak!!!
var asset = cache[asset]; var asset = cache[asset];
if (asset != null) { if (asset != null) {
switch(Type.getClass(asset)) { switch(Type.getClass(asset)) {
case lime.graphics.Image: case lime.graphics.Image:
trace("getting rid of image cause replaced"); trace("getting rid of image cause replaced");
cast(asset, lime.graphics.Image); cast(asset, lime.graphics.Image);
} }
} }
return false; return false;
} }
if (!isLocalCache) asset = '$libName:$asset'; if (!isLocalCache) asset = '$libName:$asset';
return cache.exists(asset) && cache[asset] != null; return cache.exists(asset) && cache[asset] != null;
} }
private function __parseAsset(asset:String):Bool { private function __parseAsset(asset:String):Bool {
if (!asset.startsWith(prefix)) return false; if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length); _parsedAsset = asset.substr(prefix.length);
return true; return true;
} }
#end #end
} }
+127 -127
View File
@@ -25,64 +25,64 @@ import haxe.zip.Entry;
#end #end
class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary { class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
public var zipPath:String; public var zipPath:String;
public var libName:String; public var libName:String;
public var useImageCache:Bool = false; public var useImageCache:Bool = false;
public var prefix = 'assets/'; public var prefix = 'assets/';
#if MOD_SUPPORT #if MOD_SUPPORT
public var zip:Reader; public var zip:Reader;
public var assets:Map<String, Entry> = []; public var assets:Map<String, Entry> = [];
#end #end
public function new(zipPath:String, libName:String) { public function new(zipPath:String, libName:String) {
this.zipPath = zipPath; this.zipPath = zipPath;
this.libName = libName; this.libName = libName;
this.prefix = 'assets/$libName/'; this.prefix = 'assets/$libName/';
#if MOD_SUPPORT #if MOD_SUPPORT
zip = new Reader(File.read(zipPath, true)); zip = new Reader(File.read(zipPath, true));
var entries = zip.read(); var entries = zip.read();
for(entry in entries) { for(entry in entries) {
assets[entry.fileName.toLowerCase()] = entry; assets[entry.fileName.toLowerCase()] = entry;
} }
#end #end
super(); super();
} }
#if MOD_SUPPORT #if MOD_SUPPORT
public var _parsedAsset:String; public var _parsedAsset:String;
public override function getAudioBuffer(id:String):AudioBuffer { public override function getAudioBuffer(id:String):AudioBuffer {
if (__isCacheValid(LimeAssets.cache.audio, id)) if (__isCacheValid(LimeAssets.cache.audio, id))
return LimeAssets.cache.audio.get('$libName:$id'); return LimeAssets.cache.audio.get('$libName:$id');
else { else {
if (!exists(id, "SOUND")) { if (!exists(id, "SOUND")) {
Log.error('ZipFolderLibrary: Audio Buffer at $id does not exist.'); Log.error('ZipFolderLibrary: Audio Buffer at $id does not exist.');
return null; return null;
} }
var e = AudioBuffer.fromBytes(unzip(assets[_parsedAsset])); var e = AudioBuffer.fromBytes(unzip(assets[_parsedAsset]));
return e; return e;
} }
} }
public override function getBytes(id:String):Bytes { public override function getBytes(id:String):Bytes {
if (__isCacheValid(cachedBytes, id, true)) if (__isCacheValid(cachedBytes, id, true))
return cachedBytes.get(id); return cachedBytes.get(id);
else { else {
if (!exists(id, "BINARY")) { if (!exists(id, "BINARY")) {
Log.error('ZipFolderLibrary: Bytes at $id does not exist.'); Log.error('ZipFolderLibrary: Bytes at $id does not exist.');
return null; return null;
} }
var e = Bytes.fromBytes(unzip(assets[_parsedAsset])); var e = Bytes.fromBytes(unzip(assets[_parsedAsset]));
cachedBytes.set(id, e); cachedBytes.set(id, e);
return e; return e;
} }
} }
public static function unzip(f:Entry) { public static function unzip(f:Entry) {
if (!f.compressed) if (!f.compressed)
return f.data; return f.data;
var c = new haxe.zip.Uncompress(-15); var c = new haxe.zip.Uncompress(-15);
@@ -97,86 +97,86 @@ class ZipFolderLibrary extends AssetLibrary implements ModsAssetLibrary {
return f.data; return f.data;
} }
public override function getFont(id:String):Font { public override function getFont(id:String):Font {
if (__isCacheValid(LimeAssets.cache.font, id)) if (__isCacheValid(LimeAssets.cache.font, id))
return LimeAssets.cache.font.get('$libName:$id'); return LimeAssets.cache.font.get('$libName:$id');
else { else {
if (!exists(id, "FONT")) { if (!exists(id, "FONT")) {
Log.error('ZipFolderLibrary: Font at $id does not exist.'); Log.error('ZipFolderLibrary: Font at $id does not exist.');
return null; return null;
} }
var e = Font.fromBytes(unzip(assets[_parsedAsset])); var e = Font.fromBytes(unzip(assets[_parsedAsset]));
return e; return e;
} }
} }
public override function getImage(id:String):Image { public override function getImage(id:String):Image {
if (useImageCache && __isCacheValid(LimeAssets.cache.image, id)) if (useImageCache && __isCacheValid(LimeAssets.cache.image, id))
return LimeAssets.cache.image.get('$libName:$id'); return LimeAssets.cache.image.get('$libName:$id');
else { else {
if (!exists(id, "IMAGE")) { if (!exists(id, "IMAGE")) {
Log.error('ZipFolderLibrary: Image at $id does not exist.'); Log.error('ZipFolderLibrary: Image at $id does not exist.');
return null; return null;
} }
var e = Image.fromBytes(unzip(assets[_parsedAsset])); var e = Image.fromBytes(unzip(assets[_parsedAsset]));
if (useImageCache) cachedImages.set(id, e); if (useImageCache) cachedImages.set(id, e);
return e; return e;
} }
} }
public function __parseAsset(asset:String):Bool { public function __parseAsset(asset:String):Bool {
if (!asset.startsWith(prefix)) return false; if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length).toLowerCase(); _parsedAsset = asset.substr(prefix.length).toLowerCase();
return true; return true;
} }
public function __isCacheValid(cache:Map<String, Dynamic>, asset:String, isLocal:Bool = false) { public function __isCacheValid(cache:Map<String, Dynamic>, asset:String, isLocal:Bool = false) {
if (cache.exists(isLocal ? '$libName:$asset': asset)) return true; if (cache.exists(isLocal ? '$libName:$asset': asset)) return true;
return false; return false;
} }
public override function exists(asset:String, type:String):Bool { public override function exists(asset:String, type:String):Bool {
if(!__parseAsset(asset)) return false; if(!__parseAsset(asset)) return false;
return assets[_parsedAsset] != null; return assets[_parsedAsset] != null;
} }
private function getAssetPath() { private function getAssetPath() {
return _parsedAsset; return _parsedAsset;
} }
public function getFiles(folder:String):Array<String> { public function getFiles(folder:String):Array<String> {
var content:Array<String> = []; var content:Array<String> = [];
if (!folder.endsWith("/")) folder = folder + "/"; if (!folder.endsWith("/")) folder = folder + "/";
if (!__parseAsset(folder)) return []; if (!__parseAsset(folder)) return [];
@:privateAccess @:privateAccess
for(k=>e in assets) { for(k=>e in assets) {
if (k.toLowerCase().startsWith(_parsedAsset)) { if (k.toLowerCase().startsWith(_parsedAsset)) {
var fileName = k.substr(_parsedAsset.length); var fileName = k.substr(_parsedAsset.length);
if (!fileName.contains("/")) if (!fileName.contains("/"))
content.push(fileName); content.push(fileName);
} }
} }
return content; return content;
} }
public function getFolders(folder:String):Array<String> { public function getFolders(folder:String):Array<String> {
var content:Array<String> = []; var content:Array<String> = [];
if (!folder.endsWith("/")) folder = folder + "/"; if (!folder.endsWith("/")) folder = folder + "/";
if (!__parseAsset(folder)) return []; if (!__parseAsset(folder)) return [];
@:privateAccess @:privateAccess
for(k=>e in assets) { for(k=>e in assets) {
if (k.toLowerCase().startsWith(_parsedAsset)) { if (k.toLowerCase().startsWith(_parsedAsset)) {
var fileName = k.substr(_parsedAsset.length); var fileName = k.substr(_parsedAsset.length);
if (fileName.contains("/")) if (fileName.contains("/"))
content.push(fileName.split("/")[0]); content.push(fileName.split("/")[0]);
} }
} }
return content; return content;
} }
#end #end
} }
+122 -122
View File
@@ -4,11 +4,11 @@ import funkin.windows.WindowsAPI.MessageBoxIcon;
#if windows #if windows
@:buildXml(' @:buildXml('
<target id="haxe"> <target id="haxe">
<lib name="dwmapi.lib" if="windows" /> <lib name="dwmapi.lib" if="windows" />
<lib name="shell32.lib" if="windows" /> <lib name="shell32.lib" if="windows" />
<lib name="gdi32.lib" if="windows" /> <lib name="gdi32.lib" if="windows" />
<lib name="ole32.lib" if="windows" /> <lib name="ole32.lib" if="windows" />
<lib name="uxtheme.lib" if="windows" /> <lib name="uxtheme.lib" if="windows" />
</target> </target>
') ')
@@ -28,86 +28,86 @@ import funkin.windows.WindowsAPI.MessageBoxIcon;
#include <uxtheme.h> #include <uxtheme.h>
#define SAFE_RELEASE(punk) \\ #define SAFE_RELEASE(punk) \\
if ((punk) != NULL) \\ if ((punk) != NULL) \\
{ (punk)->Release(); (punk) = NULL; } { (punk)->Release(); (punk) = NULL; }
static long lastDefId = 0; static long lastDefId = 0;
class AudioFixClient : public IMMNotificationClient { class AudioFixClient : public IMMNotificationClient {
LONG _cRef; LONG _cRef;
IMMDeviceEnumerator *_pEnumerator; IMMDeviceEnumerator *_pEnumerator;
public: public:
AudioFixClient() : AudioFixClient() :
_cRef(1), _cRef(1),
_pEnumerator(NULL) _pEnumerator(NULL)
{ {
HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator), HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_INPROC_SERVER, NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator), __uuidof(IMMDeviceEnumerator),
(void**)&_pEnumerator); (void**)&_pEnumerator);
if (result == S_OK) { if (result == S_OK) {
_pEnumerator->RegisterEndpointNotificationCallback(this); _pEnumerator->RegisterEndpointNotificationCallback(this);
} }
} }
~AudioFixClient() ~AudioFixClient()
{ {
SAFE_RELEASE(_pEnumerator); SAFE_RELEASE(_pEnumerator);
} }
ULONG STDMETHODCALLTYPE AddRef() ULONG STDMETHODCALLTYPE AddRef()
{ {
return InterlockedIncrement(&_cRef); return InterlockedIncrement(&_cRef);
} }
ULONG STDMETHODCALLTYPE Release() ULONG STDMETHODCALLTYPE Release()
{ {
ULONG ulRef = InterlockedDecrement(&_cRef); ULONG ulRef = InterlockedDecrement(&_cRef);
if (0 == ulRef) if (0 == ulRef)
{ {
delete this; delete this;
} }
return ulRef; return ulRef;
} }
HRESULT STDMETHODCALLTYPE QueryInterface( HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid, VOID **ppvInterface) REFIID riid, VOID **ppvInterface)
{ {
return S_OK; return S_OK;
} }
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId)
{ {
return S_OK; return S_OK;
}; };
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId)
{ {
return S_OK; return S_OK;
} }
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(
LPCWSTR pwstrDeviceId, LPCWSTR pwstrDeviceId,
DWORD dwNewState) DWORD dwNewState)
{ {
return S_OK; return S_OK;
} }
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(
LPCWSTR pwstrDeviceId, LPCWSTR pwstrDeviceId,
const PROPERTYKEY key) const PROPERTYKEY key)
{ {
return S_OK; return S_OK;
} }
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(
EDataFlow flow, ERole role, EDataFlow flow, ERole role,
LPCWSTR pwstrDeviceId) LPCWSTR pwstrDeviceId)
{ {
::funkin::_hx_system::Main_obj::audioDisconnected = true; ::funkin::_hx_system::Main_obj::audioDisconnected = true;
return S_OK; return S_OK;
}; };
}; };
AudioFixClient *curAudioFix; AudioFixClient *curAudioFix;
@@ -115,69 +115,69 @@ AudioFixClient *curAudioFix;
@:dox(hide) @:dox(hide)
class Windows { class Windows {
public static var __audioChangeCallback:Void->Void = function() { public static var __audioChangeCallback:Void->Void = function() {
trace("test"); trace("test");
}; };
@:functionCode(' @:functionCode('
if (!curAudioFix) curAudioFix = new AudioFixClient(); if (!curAudioFix) curAudioFix = new AudioFixClient();
') ')
public static function registerAudio() { public static function registerAudio() {
funkin.system.Main.audioDisconnected = false; funkin.system.Main.audioDisconnected = false;
} }
@:functionCode(' @:functionCode('
int darkMode = enable ? 1 : 0; int darkMode = enable ? 1 : 0;
HWND window = GetActiveWindow(); HWND window = GetActiveWindow();
if (S_OK != DwmSetWindowAttribute(window, 19, &darkMode, sizeof(darkMode))) { if (S_OK != DwmSetWindowAttribute(window, 19, &darkMode, sizeof(darkMode))) {
DwmSetWindowAttribute(window, 20, &darkMode, sizeof(darkMode)); DwmSetWindowAttribute(window, 20, &darkMode, sizeof(darkMode));
} }
') ')
public static function setDarkMode(enable:Bool) {} public static function setDarkMode(enable:Bool) {}
@:functionCode(' @:functionCode('
// https://stackoverflow.com/questions/15543571/allocconsole-not-displaying-cout // https://stackoverflow.com/questions/15543571/allocconsole-not-displaying-cout
if (!AllocConsole()) if (!AllocConsole())
return; return;
freopen("CONIN$", "r", stdin); freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr); freopen("CONOUT$", "w", stderr);
') ')
public static function allocConsole() { public static function allocConsole() {
} }
@:functionCode(' @:functionCode('
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(console, color); SetConsoleTextAttribute(console, color);
') ')
public static function setConsoleColors(color:Int) { public static function setConsoleColors(color:Int) {
} }
@:functionCode(' @:functionCode('
system("CLS"); system("CLS");
std::cout<< "" <<std::flush; std::cout<< "" <<std::flush;
') ')
public static function clearScreen() { public static function clearScreen() {
} }
@:functionCode(' @:functionCode('
MessageBox(GetActiveWindow(), message, caption, icon | MB_SETFOREGROUND); MessageBox(GetActiveWindow(), message, caption, icon | MB_SETFOREGROUND);
') ')
public static function showMessageBox(caption:String, message:String, icon:MessageBoxIcon = MSG_WARNING) { public static function showMessageBox(caption:String, message:String, icon:MessageBoxIcon = MSG_WARNING) {
} }
@:functionCode(' @:functionCode('
SetProcessDPIAware(); SetProcessDPIAware();
') ')
public static function registerAsDPICompatible() {} public static function registerAsDPICompatible() {}
@:functionCode(" @:functionCode("
// simple but effective code // simple but effective code
+96 -96
View File
@@ -10,114 +10,114 @@ import funkin.options.categories.*;
import funkin.options.TreeMenu; import funkin.options.TreeMenu;
class OptionsMenu extends TreeMenu { class OptionsMenu extends TreeMenu {
public static var mainOptions:Array<OptionCategory> = [ public static var mainOptions:Array<OptionCategory> = [
{ {
name: 'Controls', name: 'Controls',
desc: 'Change Controls for Player 1 and Player 2!', desc: 'Change Controls for Player 1 and Player 2!',
state: null, state: null,
substate: funkin.options.keybinds.KeybindsOptions substate: funkin.options.keybinds.KeybindsOptions
}, },
{ {
name: 'Gameplay >', name: 'Gameplay >',
desc: 'Change Gameplay options such as Downscroll, Scroll Speed, Naughtyness...', desc: 'Change Gameplay options such as Downscroll, Scroll Speed, Naughtyness...',
state: GameplayOptions state: GameplayOptions
}, },
{ {
name: 'Appearance >', name: 'Appearance >',
desc: 'Change Appearance options such as Flashing menus...', desc: 'Change Appearance options such as Flashing menus...',
state: AppearanceOptions state: AppearanceOptions
}, },
{ {
name: 'Miscellaneous >', name: 'Miscellaneous >',
desc: 'Use this menu to reset save data or engine settings.', desc: 'Use this menu to reset save data or engine settings.',
state: MiscOptions state: MiscOptions
} }
]; ];
public override function create() { public override function create() {
super.create(); super.create();
CoolUtil.playMenuSong(); CoolUtil.playMenuSong();
var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue')); var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue'));
// bg.scrollFactor.set(); // bg.scrollFactor.set();
bg.scale.set(1.15, 1.15); bg.scale.set(1.15, 1.15);
bg.updateHitbox(); bg.updateHitbox();
bg.screenCenter(); bg.screenCenter();
bg.scrollFactor.set(); bg.scrollFactor.set();
bg.antialiasing = true; bg.antialiasing = true;
add(bg); add(bg);
main = new OptionsScreen("Options", "Select a category to continue.", [for(o in mainOptions) new TextOption(o.name, o.desc, function() { main = new OptionsScreen("Options", "Select a category to continue.", [for(o in mainOptions) new TextOption(o.name, o.desc, function() {
if (o.substate != null) { if (o.substate != null) {
persistentUpdate = false; persistentUpdate = false;
persistentDraw = true; persistentDraw = true;
if (o.substate is MusicBeatSubstate) { if (o.substate is MusicBeatSubstate) {
openSubState(o.substate); openSubState(o.substate);
} else { } else {
openSubState(Type.createInstance(o.substate, [])); openSubState(Type.createInstance(o.substate, []));
} }
} else { } else {
if (o.state is OptionsScreen) { if (o.state is OptionsScreen) {
optionsTree.add(o.state); optionsTree.add(o.state);
} else { } else {
optionsTree.add(Type.createInstance(o.state, [])); optionsTree.add(Type.createInstance(o.state, []));
} }
} }
})]); })]);
var xmlPath = Paths.xml("config/options"); var xmlPath = Paths.xml("config/options");
for(source in [funkin.system.AssetsLibraryList.AssetSource.SOURCE, funkin.system.AssetsLibraryList.AssetSource.MODS]) { for(source in [funkin.system.AssetsLibraryList.AssetSource.SOURCE, funkin.system.AssetsLibraryList.AssetSource.MODS]) {
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) { if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) {
var access:Access = null; var access:Access = null;
try { try {
access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT", source))); access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT", source)));
} catch(e) { } catch(e) {
Logs.trace('Error while parsing options.xml: ${Std.string(e)}', ERROR); Logs.trace('Error while parsing options.xml: ${Std.string(e)}', ERROR);
} }
if (access != null) if (access != null)
for(o in parseOptionsFromXML(access)) for(o in parseOptionsFromXML(access))
main.add(o); main.add(o);
} }
} }
} }
public override function exit() { public override function exit() {
Options.save(); Options.save();
Options.applySettings(); Options.applySettings();
super.exit(); super.exit();
} }
/** /**
* XML STUFF * XML STUFF
*/ */
public function parseOptionsFromXML(xml:Access):Array<OptionType> { public function parseOptionsFromXML(xml:Access):Array<OptionType> {
var options:Array<OptionType> = []; var options:Array<OptionType> = [];
for(node in xml.elements) { for(node in xml.elements) {
if (!node.has.name) { if (!node.has.name) {
Logs.trace("An option node requires a name attribute.", WARNING); Logs.trace("An option node requires a name attribute.", WARNING);
continue; continue;
} }
var name = node.getAtt("name"); var name = node.getAtt("name");
var desc = node.getAtt("desc").getDefault("No Description"); var desc = node.getAtt("desc").getDefault("No Description");
switch(node.name) { switch(node.name) {
case "checkbox": case "checkbox":
if (!node.has.id) { if (!node.has.id) {
Logs.trace("A checkbox option requires an \"id\" for option saving.", WARNING); Logs.trace("A checkbox option requires an \"id\" for option saving.", WARNING);
continue; continue;
} }
options.push(new Checkbox(name, desc, node.att.id, FlxG.save.data)); options.push(new Checkbox(name, desc, node.att.id, FlxG.save.data));
case "menu": case "menu":
options.push(new TextOption(name + " >", desc, function() { options.push(new TextOption(name + " >", desc, function() {
optionsTree.add(new OptionsScreen(name, desc, parseOptionsFromXML(node))); optionsTree.add(new OptionsScreen(name, desc, parseOptionsFromXML(node)));
})); }));
} }
} }
return options; return options;
} }
} }
+48 -48
View File
@@ -3,67 +3,67 @@ package funkin.options;
import funkin.options.type.OptionType; import funkin.options.type.OptionType;
class OptionsScreen extends FlxTypedSpriteGroup<OptionType> { class OptionsScreen extends FlxTypedSpriteGroup<OptionType> {
public static var optionHeight:Float = 120; public static var optionHeight:Float = 120;
public var parent:OptionsTree; public var parent:OptionsTree;
public var curSelected:Int = 0; public var curSelected:Int = 0;
public var id:Int = 0; public var id:Int = 0;
private var __firstFrame:Bool = true; private var __firstFrame:Bool = true;
public var name:String; public var name:String;
public var desc:String; public var desc:String;
public function new(name:String, desc:String, ?options:Array<OptionType>) { public function new(name:String, desc:String, ?options:Array<OptionType>) {
super(); super();
this.name = name; this.name = name;
this.desc = desc; this.desc = desc;
if (options != null) for(o in options) add(o); if (options != null) for(o in options) add(o);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
var controls = PlayerSettings.solo.controls; var controls = PlayerSettings.solo.controls;
changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0) - FlxG.mouse.wheel); changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0) - FlxG.mouse.wheel);
x = id * FlxG.width; x = id * FlxG.width;
for(k=>option in members) { for(k=>option in members) {
var y:Float = ((FlxG.height - optionHeight) / 2) + ((k - curSelected) * optionHeight); var y:Float = ((FlxG.height - optionHeight) / 2) + ((k - curSelected) * optionHeight);
option.selected = false; option.selected = false;
option.y = __firstFrame ? y : CoolUtil.fpsLerp(option.y, y, 0.25); option.y = __firstFrame ? y : CoolUtil.fpsLerp(option.y, y, 0.25);
option.x = x + (-50 + (Math.abs(Math.cos((option.y + (optionHeight / 2) - (FlxG.camera.scroll.y + (FlxG.height / 2))) / (FlxG.height * 1.25) * Math.PI)) * 150)); option.x = x + (-50 + (Math.abs(Math.cos((option.y + (optionHeight / 2) - (FlxG.camera.scroll.y + (FlxG.height / 2))) / (FlxG.height * 1.25) * Math.PI)) * 150));
} }
if (__firstFrame) { if (__firstFrame) {
__firstFrame = false; __firstFrame = false;
return; return;
} }
if (members.length > 0) { if (members.length > 0) {
members[curSelected].selected = true; members[curSelected].selected = true;
if (controls.ACCEPT || FlxG.mouse.justReleased) if (controls.ACCEPT || FlxG.mouse.justReleased)
members[curSelected].onSelect(); members[curSelected].onSelect();
} }
if (controls.BACK || FlxG.mouse.justReleasedRight) if (controls.BACK || FlxG.mouse.justReleasedRight)
close(); close();
} }
public function close() { public function close() {
onClose(this); onClose(this);
} }
public function changeSelection(sel:Int) { public function changeSelection(sel:Int) {
if (members.length <= 0 || sel == 0) return; if (members.length <= 0 || sel == 0) return;
CoolUtil.playMenuSFX(SCROLL); CoolUtil.playMenuSFX(SCROLL);
curSelected = FlxMath.wrap(curSelected + sel, 0, members.length-1); curSelected = FlxMath.wrap(curSelected + sel, 0, members.length-1);
for(o in members) for(o in members)
members[curSelected].selected = true; members[curSelected].selected = true;
} }
public dynamic function onClose(o:OptionsScreen) {} public dynamic function onClose(o:OptionsScreen) {}
} }
+57 -57
View File
@@ -2,73 +2,73 @@ package funkin.options;
import flixel.util.FlxDestroyUtil; import flixel.util.FlxDestroyUtil;
class OptionsTree extends FlxTypedGroup<OptionsScreen> { class OptionsTree extends FlxTypedGroup<OptionsScreen> {
public var lastMenu:OptionsScreen; public var lastMenu:OptionsScreen;
public override function new() { public override function new() {
super(); super();
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
var last = members.last(); var last = members.last();
if (last != null) if (last != null)
last.update(elapsed); last.update(elapsed);
} }
public override function draw() { public override function draw() {
super.draw(); super.draw();
if (lastMenu != null) { if (lastMenu != null) {
lastMenu.draw(); lastMenu.draw();
} }
} }
public override function add(m:OptionsScreen) { public override function add(m:OptionsScreen) {
super.add(m); super.add(m);
setup(m); setup(m);
clearLastMenu(); clearLastMenu();
onMenuChange(); onMenuChange();
return m; return m;
} }
public override function insert(pos:Int, m:OptionsScreen) { public override function insert(pos:Int, m:OptionsScreen) {
var last = members.last(); var last = members.last();
super.insert(pos, m); super.insert(pos, m);
setup(m); setup(m);
if (last != members.last()) if (last != members.last())
onMenuChange(); onMenuChange();
return m; return m;
} }
public function setup(m:OptionsScreen) { public function setup(m:OptionsScreen) {
m.onClose = __subMenuClose; m.onClose = __subMenuClose;
m.id = members.indexOf(m); m.id = members.indexOf(m);
m.parent = this; m.parent = this;
m.update(0); m.update(0);
} }
function __subMenuClose(m:OptionsScreen) { function __subMenuClose(m:OptionsScreen) {
clearLastMenu(); clearLastMenu();
lastMenu = m; lastMenu = m;
remove(m, true); remove(m, true);
onMenuChange(); onMenuChange();
onMenuClose(m); onMenuClose(m);
} }
public function clearLastMenu() { public function clearLastMenu() {
if (lastMenu != null) { if (lastMenu != null) {
lastMenu.destroy(); lastMenu.destroy();
lastMenu = null; lastMenu = null;
} }
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
lastMenu = FlxDestroyUtil.destroy(lastMenu); lastMenu = FlxDestroyUtil.destroy(lastMenu);
} }
public dynamic function onMenuChange() { public dynamic function onMenuChange() {
} }
public dynamic function onMenuClose(m:OptionsScreen) { public dynamic function onMenuClose(m:OptionsScreen) {
} }
} }
+71 -71
View File
@@ -10,102 +10,102 @@ import funkin.options.type.OptionType;
import funkin.options.categories.*; import funkin.options.categories.*;
class TreeMenu extends MusicBeatState { class TreeMenu extends MusicBeatState {
public var main:OptionsScreen; public var main:OptionsScreen;
public var optionsTree:OptionsTree; public var optionsTree:OptionsTree;
public var pathLabel:FunkinText; public var pathLabel:FunkinText;
public var pathDesc:FunkinText; public var pathDesc:FunkinText;
public var pathBG:FlxSprite; public var pathBG:FlxSprite;
public var lastState:Class<FlxState> = Type.getClass(FlxG.state); public var lastState:Class<FlxState> = Type.getClass(FlxG.state);
public function new() { public function new() {
super(); super();
} }
public override function createPost() { public override function createPost() {
if (main == null) throw "\"main\" variable has not been set in extended class!"; if (main == null) throw "\"main\" variable has not been set in extended class!";
FlxG.camera.scroll.set(-FlxG.width, 0); FlxG.camera.scroll.set(-FlxG.width, 0);
pathLabel = new FunkinText(4, 4, FlxG.width - 8, "> Tree Menu", 32, false); pathLabel = new FunkinText(4, 4, FlxG.width - 8, "> Tree Menu", 32, false);
pathLabel.scrollFactor.set(); pathLabel.scrollFactor.set();
pathDesc = new FunkinText(4, pathLabel.y + pathLabel.height + 2, FlxG.width - 8, "Current Tree Menu Description", 16, false); pathDesc = new FunkinText(4, pathLabel.y + pathLabel.height + 2, FlxG.width - 8, "Current Tree Menu Description", 16, false);
pathDesc.scrollFactor.set(); pathDesc.scrollFactor.set();
pathBG = new FlxSprite().makeGraphic(1, 1, 0xFF000000); pathBG = new FlxSprite().makeGraphic(1, 1, 0xFF000000);
pathBG.scale.set(FlxG.width, pathDesc.y + pathDesc.height + 2); pathBG.scale.set(FlxG.width, pathDesc.y + pathDesc.height + 2);
pathBG.updateHitbox(); pathBG.updateHitbox();
pathBG.alpha = 0.25; pathBG.alpha = 0.25;
pathBG.scrollFactor.set(); pathBG.scrollFactor.set();
optionsTree = new OptionsTree(); optionsTree = new OptionsTree();
optionsTree.onMenuChange = onMenuChange; optionsTree.onMenuChange = onMenuChange;
optionsTree.onMenuClose = onMenuClose; optionsTree.onMenuClose = onMenuClose;
optionsTree.add(main); optionsTree.add(main);
add(optionsTree); add(optionsTree);
add(pathBG); add(pathBG);
add(pathLabel); add(pathLabel);
add(pathDesc); add(pathDesc);
super.createPost(); super.createPost();
} }
public function onMenuChange() { public function onMenuChange() {
if (optionsTree.members.length <= 0) { if (optionsTree.members.length <= 0) {
exit(); exit();
} else { } else {
if (menuChangeTween != null) if (menuChangeTween != null)
menuChangeTween.cancel(); menuChangeTween.cancel();
menuChangeTween = FlxTween.tween(FlxG.camera.scroll, {x: FlxG.width * Math.max(0, (optionsTree.members.length-1))}, 1.5, {ease: menuTransitionEase, onComplete: function(t) { menuChangeTween = FlxTween.tween(FlxG.camera.scroll, {x: FlxG.width * Math.max(0, (optionsTree.members.length-1))}, 1.5, {ease: menuTransitionEase, onComplete: function(t) {
optionsTree.clearLastMenu(); optionsTree.clearLastMenu();
menuChangeTween = null; menuChangeTween = null;
}}); }});
var t = ""; var t = "";
for(o in optionsTree.members) for(o in optionsTree.members)
t += '${o.name} > '; t += '${o.name} > ';
pathLabel.text = t; pathLabel.text = t;
pathDesc.text = optionsTree.members.last().desc; pathDesc.text = optionsTree.members.last().desc;
pathBG.scale.set(FlxG.width, pathDesc.y + pathDesc.height + 2); pathBG.scale.set(FlxG.width, pathDesc.y + pathDesc.height + 2);
pathBG.updateHitbox(); pathBG.updateHitbox();
} }
} }
public function exit() { public function exit() {
FlxG.switchState((lastState != null) ? Type.createInstance(lastState, []) : new MainMenuState()); FlxG.switchState((lastState != null) ? Type.createInstance(lastState, []) : new MainMenuState());
} }
public function onMenuClose(m:OptionsScreen) { public function onMenuClose(m:OptionsScreen) {
CoolUtil.playMenuSFX(CANCEL); CoolUtil.playMenuSFX(CANCEL);
} }
var menuChangeTween:FlxTween; var menuChangeTween:FlxTween;
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
// in case path gets so long it goes offscreen // in case path gets so long it goes offscreen
pathLabel.x = lerp(pathLabel.x, Math.max(0, FlxG.width - 4 - pathLabel.width), 0.125); pathLabel.x = lerp(pathLabel.x, Math.max(0, FlxG.width - 4 - pathLabel.width), 0.125);
} }
public static inline function menuTransitionEase(e:Float) public static inline function menuTransitionEase(e:Float)
return FlxEase.quintInOut(FlxEase.cubeOut(e)); return FlxEase.quintInOut(FlxEase.cubeOut(e));
} }
typedef OptionCategory = { typedef OptionCategory = {
var name:String; var name:String;
var desc:String; var desc:String;
var state:OneOfTwo<OptionsScreen, Class<OptionsScreen>>; var state:OneOfTwo<OptionsScreen, Class<OptionsScreen>>;
var ?substate:OneOfTwo<MusicBeatSubstate, Class<MusicBeatSubstate>>; var ?substate:OneOfTwo<MusicBeatSubstate, Class<MusicBeatSubstate>>;
} }
typedef OptionTypeDef = { typedef OptionTypeDef = {
var type:Class<OptionType>; var type:Class<OptionType>;
var args:Array<Dynamic>; var args:Array<Dynamic>;
} }
@@ -1,27 +1,27 @@
package funkin.options.categories; package funkin.options.categories;
class AppearanceOptions extends OptionsScreen { class AppearanceOptions extends OptionsScreen {
public override function new() { public override function new() {
super("Appearance", "Change Appearance options such as Flashing menus..."); super("Appearance", "Change Appearance options such as Flashing menus...");
add(new Checkbox( add(new Checkbox(
"Antialiasing", "Antialiasing",
"If unchecked, will disable antialiasing on every sprite. Can boost performances at the cost of sharper, more pixely sprites", "If unchecked, will disable antialiasing on every sprite. Can boost performances at the cost of sharper, more pixely sprites",
"antialiasing")); "antialiasing"));
add(new Checkbox( add(new Checkbox(
"Pixel Perfect Effect", "Pixel Perfect Effect",
"If checked, Week 6 will have a pixel perfect effect to it enabled, aligning every pixel on the screen.", "If checked, Week 6 will have a pixel perfect effect to it enabled, aligning every pixel on the screen.",
"week6PixelPerfect")); "week6PixelPerfect"));
add(new Checkbox( add(new Checkbox(
"Flashing Menu", "Flashing Menu",
"If unchecked, will disable menu flashing when you select an option in the Main Menu, and other flashs will be slower", "If unchecked, will disable menu flashing when you select an option in the Main Menu, and other flashs will be slower",
"flashingMenu")); "flashingMenu"));
add(new Checkbox( add(new Checkbox(
"Low Memory Mode", "Low Memory Mode",
"If checked, will disable certain background elements in stages to reduce memory usage.", "If checked, will disable certain background elements in stages to reduce memory usage.",
"lowMemoryMode")); "lowMemoryMode"));
add(new Checkbox( add(new Checkbox(
"Auto Pause", "Auto Pause",
"If checked, switching windows will pause the game", "If checked, switching windows will pause the game",
"autoPause")); "autoPause"));
} }
} }
@@ -1,23 +1,23 @@
package funkin.options.categories; package funkin.options.categories;
class GameplayOptions extends OptionsScreen { class GameplayOptions extends OptionsScreen {
public override function new() { public override function new() {
super("Gameplay", 'Change Gameplay options such as Downscroll, Scroll Speed, Naughtyness...'); super("Gameplay", 'Change Gameplay options such as Downscroll, Scroll Speed, Naughtyness...');
add(new Checkbox( add(new Checkbox(
"Downscroll", "Downscroll",
"If checked, notes will go from up to down instead of down to up, like if they were falling", "If checked, notes will go from up to down instead of down to up, like if they were falling",
"downscroll")); "downscroll"));
add(new Checkbox( add(new Checkbox(
"Ghost Tapping", "Ghost Tapping",
"If unchecked, trying to hit any strum that have no note that can be hit will cause a miss.", "If unchecked, trying to hit any strum that have no note that can be hit will cause a miss.",
"ghostTapping")); "ghostTapping"));
add(new Checkbox( add(new Checkbox(
"Naughtyness", "Naughtyness",
"If unchecked, will censor Week 7 cutscenes", "If unchecked, will censor Week 7 cutscenes",
"naughtyness")); "naughtyness"));
add(new Checkbox( add(new Checkbox(
"Camera Zoom on Beat", "Camera Zoom on Beat",
"If unchecked, will disable camera zooming every 4 beats", "If unchecked, will disable camera zooming every 4 beats",
"camZoomOnBeat")); "camZoomOnBeat"));
} }
} }
+27 -27
View File
@@ -2,31 +2,31 @@ package funkin.options.categories;
class MiscOptions extends OptionsScreen { class MiscOptions extends OptionsScreen {
public override function new() { public override function new() {
super("Miscellaneous", "Use this menu to reset save data or engine settings."); super("Miscellaneous", "Use this menu to reset save data or engine settings.");
#if UPDATE_CHECKING #if UPDATE_CHECKING
add(new Checkbox( add(new Checkbox(
"Enable Beta Updates", "Enable Beta Updates",
"If checked, will also include beta (prereleases) updates in the update checking.", "If checked, will also include beta (prereleases) updates in the update checking.",
"betaUpdates"));, "betaUpdates"));,
add(new TextOption( add(new TextOption(
"Check for Updates", "Check for Updates",
"Select this option to check for new engine updates.", "Select this option to check for new engine updates.",
function() { function() {
var report = funkin.updating.UpdateUtil.checkForUpdates(); var report = funkin.updating.UpdateUtil.checkForUpdates();
if (report.newUpdate) { if (report.newUpdate) {
FlxG.switchState(new funkin.updating.UpdateAvailableScreen(report)); FlxG.switchState(new funkin.updating.UpdateAvailableScreen(report));
} else { } else {
CoolUtil.playMenuSFX(CANCEL); CoolUtil.playMenuSFX(CANCEL);
updateDescText("No update found."); updateDescText("No update found.");
} }
}));, }));,
#end #end
add(new TextOption( add(new TextOption(
"Reset Save Data", "Reset Save Data",
"Select this option to reset save data. This will remove all of your highscores", "Select this option to reset save data. This will remove all of your highscores",
function() { function() {
// TODO: SAVE DATA RESETTING // TODO: SAVE DATA RESETTING
})); }));
} }
} }
@@ -7,32 +7,32 @@ import flixel.util.FlxColor;
import flixel.input.keyboard.FlxKey; import flixel.input.keyboard.FlxKey;
class ChangeKeybindSubState extends MusicBeatSubstate { class ChangeKeybindSubState extends MusicBeatSubstate {
var callback:FlxKey->Void; var callback:FlxKey->Void;
var cancelCallback:Void->Void; var cancelCallback:Void->Void;
var stillPressed:Bool = true; var stillPressed:Bool = true;
public override function new(callback:FlxKey->Void, cancelCallback:Void->Void) { public override function new(callback:FlxKey->Void, cancelCallback:Void->Void) {
this.callback = callback; this.callback = callback;
this.cancelCallback = cancelCallback; this.cancelCallback = cancelCallback;
super(); super();
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (stillPressed && controls.ACCEPT) if (stillPressed && controls.ACCEPT)
return; return;
stillPressed = false; stillPressed = false;
var key:FlxKey = FlxG.keys.firstJustPressed(); var key:FlxKey = FlxG.keys.firstJustPressed();
if (cast(key, Int) <= 0) return; if (cast(key, Int) <= 0) return;
if (key == ESCAPE && !FlxG.keys.pressed.SHIFT) { if (key == ESCAPE && !FlxG.keys.pressed.SHIFT) {
close(); close();
cancelCallback(); cancelCallback();
return; return;
} }
close(); close();
callback(key); callback(key);
return; return;
} }
} }
@@ -9,95 +9,95 @@ import flixel.input.keyboard.FlxKey;
using StringTools; using StringTools;
class KeybindSetting extends FlxTypedSpriteGroup<FlxSprite> { class KeybindSetting extends FlxTypedSpriteGroup<FlxSprite> {
public var title:Alphabet; public var title:Alphabet;
public var bind1:Alphabet; public var bind1:Alphabet;
public var bind2:Alphabet; public var bind2:Alphabet;
public var icon:FlxSprite; public var icon:FlxSprite;
public var changingKeybind:Int = -1; public var changingKeybind:Int = -1;
public var p2Selected:Bool = false; public var p2Selected:Bool = false;
public var value:String; public var value:String;
public var option1:Null<FlxKey>; public var option1:Null<FlxKey>;
public var option2:Null<FlxKey>; public var option2:Null<FlxKey>;
public function new(x:Float, y:Float, name:String, value:String, ?sparrowIcon:String, ?sparrowAnim:String) { public function new(x:Float, y:Float, name:String, value:String, ?sparrowIcon:String, ?sparrowAnim:String) {
super(); super();
this.value = value; this.value = value;
title = new Alphabet(0, 0, name, true); title = new Alphabet(0, 0, name, true);
add(title); add(title);
var controlArrayP1:Array<FlxKey> = Reflect.field(Options, 'P1_${value}'); var controlArrayP1:Array<FlxKey> = Reflect.field(Options, 'P1_${value}');
var controlArrayP2:Array<FlxKey> = Reflect.field(Options, 'P2_${value}'); var controlArrayP2:Array<FlxKey> = Reflect.field(Options, 'P2_${value}');
option1 = controlArrayP1[0]; option1 = controlArrayP1[0];
option2 = controlArrayP2[0]; option2 = controlArrayP2[0];
for(i in 1...3) { for(i in 1...3) {
var b = null; var b = null;
if (i == 1) if (i == 1)
b = bind1 = new Alphabet(0, 0, "", false); b = bind1 = new Alphabet(0, 0, "", false);
else else
b = bind2 = new Alphabet(0, 0, "", false); b = bind2 = new Alphabet(0, 0, "", false);
b.setPosition(FlxG.width * (0.25 * (i+1)) - x, -60); b.setPosition(FlxG.width * (0.25 * (i+1)) - x, -60);
add(b); add(b);
} }
updateText(); updateText();
if (sparrowIcon != null) { if (sparrowIcon != null) {
icon = new FlxSprite(); icon = new FlxSprite();
icon.frames = Paths.getFrames(sparrowIcon); icon.frames = Paths.getFrames(sparrowIcon);
icon.antialiasing = true; icon.antialiasing = true;
icon.animation.addByPrefix('icon', sparrowAnim, 24, true); icon.animation.addByPrefix('icon', sparrowAnim, 24, true);
icon.animation.play('icon'); icon.animation.play('icon');
icon.setGraphicSize(75, 75); icon.setGraphicSize(75, 75);
icon.updateHitbox(); icon.updateHitbox();
var min = Math.min(icon.scale.x, icon.scale.y); var min = Math.min(icon.scale.x, icon.scale.y);
icon.scale.set(min, min); icon.scale.set(min, min);
add(icon); add(icon);
title.setPosition(100, 0); title.setPosition(100, 0);
} }
setPosition(x, y); setPosition(x, y);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
bind1.alpha = (p2Selected ? 0.2 : 1) / alpha; bind1.alpha = (p2Selected ? 0.2 : 1) / alpha;
bind2.alpha = (p2Selected ? 1 : 0.2) / alpha; bind2.alpha = (p2Selected ? 1 : 0.2) / alpha;
bind1.alpha *= alpha; bind1.alpha *= alpha;
bind2.alpha *= alpha; bind2.alpha *= alpha;
} }
public function changeKeybind(callback:Void->Void, cancelCallback:Void->Void, p2:Bool = false) { public function changeKeybind(callback:Void->Void, cancelCallback:Void->Void, p2:Bool = false) {
var flicker = FlxFlicker.flicker(this, 0, Options.flashingMenu ? 0.06 : 0.15, true, false, function(t) {}); var flicker = FlxFlicker.flicker(this, 0, Options.flashingMenu ? 0.06 : 0.15, true, false, function(t) {});
KeybindsOptions.instance.persistentDraw = true; KeybindsOptions.instance.persistentDraw = true;
KeybindsOptions.instance.persistentUpdate = false; KeybindsOptions.instance.persistentUpdate = false;
KeybindsOptions.instance.openSubState(new ChangeKeybindSubState(function(key:FlxKey) { KeybindsOptions.instance.openSubState(new ChangeKeybindSubState(function(key:FlxKey) {
flicker.stop(); flicker.stop();
flicker.destroy(); flicker.destroy();
if (p2) if (p2)
Reflect.setField(Options, 'P2_$value', [option2 = key]); Reflect.setField(Options, 'P2_$value', [option2 = key]);
else else
Reflect.setField(Options, 'P1_$value', [option1 = key]); Reflect.setField(Options, 'P1_$value', [option1 = key]);
updateText(); updateText();
callback(); callback();
}, function() { }, function() {
flicker.stop(); flicker.stop();
flicker.destroy(); flicker.destroy();
if (p2) if (p2)
Reflect.setField(Options, 'P2_$value', [option2 = 0]); Reflect.setField(Options, 'P2_$value', [option2 = 0]);
else else
Reflect.setField(Options, 'P1_$value', [option1 = 0]); Reflect.setField(Options, 'P1_$value', [option1 = 0]);
cancelCallback(); cancelCallback();
})); }));
} }
public function updateText() { public function updateText() {
bind1.text = '${CoolUtil.keyToString(option1)}'; bind1.text = '${CoolUtil.keyToString(option1)}';
bind2.text = '${CoolUtil.keyToString(option2)}'; bind2.text = '${CoolUtil.keyToString(option2)}';
} }
} }
+217 -217
View File
@@ -8,247 +8,247 @@ import flixel.input.keyboard.FlxKey;
using StringTools; using StringTools;
class KeybindsOptions extends MusicBeatSubstate { class KeybindsOptions extends MusicBeatSubstate {
public static var instance:KeybindsOptions; public static var instance:KeybindsOptions;
public var categories = [ public var categories = [
{ {
name: 'Notes', name: 'Notes',
settings: [ settings: [
{ {
name: '{noteLeft}', name: '{noteLeft}',
control: 'NOTE_LEFT' control: 'NOTE_LEFT'
}, },
{ {
name: '{noteDown}', name: '{noteDown}',
control: 'NOTE_DOWN' control: 'NOTE_DOWN'
}, },
{ {
name: '{noteUp}', name: '{noteUp}',
control: 'NOTE_UP' control: 'NOTE_UP'
}, },
{ {
name: '{noteRight}', name: '{noteRight}',
control: 'NOTE_RIGHT' control: 'NOTE_RIGHT'
}, },
] ]
}, },
{ {
name: 'UI', name: 'UI',
settings: [ settings: [
{ {
name: 'Left', name: 'Left',
control: 'LEFT' control: 'LEFT'
}, },
{ {
name: 'Down', name: 'Down',
control: 'DOWN' control: 'DOWN'
}, },
{ {
name: 'Up', name: 'Up',
control: 'UP' control: 'UP'
}, },
{ {
name: 'Right', name: 'Right',
control: 'RIGHT' control: 'RIGHT'
}, },
{ {
name: 'Accept', name: 'Accept',
control: 'ACCEPT' control: 'ACCEPT'
}, },
{ {
name: 'Back', name: 'Back',
control: 'BACK' control: 'BACK'
}, },
{ {
name: 'Reset', name: 'Reset',
control: 'RESET' control: 'RESET'
}, },
{ {
name: 'Pause', name: 'Pause',
control: 'PAUSE' control: 'PAUSE'
}, },
] ]
}, },
{ {
name: 'Engine', name: 'Engine',
settings: [ settings: [
{ {
name: 'Switch Mod', name: 'Switch Mod',
control: 'SWITCHMOD' control: 'SWITCHMOD'
}, },
] ]
} }
]; ];
public var settingCam:FlxCamera; public var settingCam:FlxCamera;
public var p2Selected:Bool = false; public var p2Selected:Bool = false;
public var curSelected:Int = 0; public var curSelected:Int = 0;
public var canSelect:Bool = true; public var canSelect:Bool = true;
public var alphabets:FlxTypedGroup<KeybindSetting>; public var alphabets:FlxTypedGroup<KeybindSetting>;
public var bg:FlxSprite; public var bg:FlxSprite;
public var coloredBG:FlxSprite; public var coloredBG:FlxSprite;
public var noteColors:Array<FlxColor> = [ public var noteColors:Array<FlxColor> = [
0xFFC24B99, 0xFFC24B99,
0xFF00FFFF, 0xFF00FFFF,
0xFF12FA05, 0xFF12FA05,
0xFFF9393F 0xFFF9393F
]; ];
public var camFollow:FlxObject = new FlxObject(0, 0, 2, 2); public var camFollow:FlxObject = new FlxObject(0, 0, 2, 2);
var isSubState:Bool = false; var isSubState:Bool = false;
public override function create() { public override function create() {
super.create(); super.create();
instance = this; instance = this;
isSubState = FlxG.state != this; isSubState = FlxG.state != this;
alphabets = new FlxTypedGroup<KeybindSetting>(); alphabets = new FlxTypedGroup<KeybindSetting>();
bg = new FlxSprite(-80).loadAnimatedGraphic(Paths.image(isSubState ? 'menus/menuTransparent' : 'menus/menuBGBlue')); bg = new FlxSprite(-80).loadAnimatedGraphic(Paths.image(isSubState ? 'menus/menuTransparent' : 'menus/menuBGBlue'));
coloredBG = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuDesat')); coloredBG = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuDesat'));
for(bg in [bg, coloredBG]) { for(bg in [bg, coloredBG]) {
bg.scrollFactor.set(); bg.scrollFactor.set();
bg.scale.set(1.15, 1.15); bg.scale.set(1.15, 1.15);
bg.updateHitbox(); bg.updateHitbox();
bg.screenCenter(); bg.screenCenter();
bg.antialiasing = true; bg.antialiasing = true;
add(bg); add(bg);
} }
coloredBG.alpha = 0; coloredBG.alpha = 0;
if (isSubState) { if (isSubState) {
// is substate, opened from pause menu // is substate, opened from pause menu
if (settingCam == null) { if (settingCam == null) {
settingCam = new FlxCamera(); settingCam = new FlxCamera();
settingCam.bgColor = 0xAA000000; settingCam.bgColor = 0xAA000000;
FlxG.cameras.add(settingCam, false); FlxG.cameras.add(settingCam, false);
} }
cameras = [settingCam]; cameras = [settingCam];
bg.alpha = 0; bg.alpha = 0;
settingCam.follow(camFollow, LOCKON, 0.125); settingCam.follow(camFollow, LOCKON, 0.125);
} else { } else {
FlxG.camera.follow(camFollow, LOCKON, 0.125); FlxG.camera.follow(camFollow, LOCKON, 0.125);
} }
var k:Int = 0; var k:Int = 0;
for(category in categories) { for(category in categories) {
k++; k++;
var title = new Alphabet(0, k * 75, category.name, true); var title = new Alphabet(0, k * 75, category.name, true);
title.screenCenter(X); title.screenCenter(X);
add(title); add(title);
k++; k++;
for(e in category.settings) { for(e in category.settings) {
var sparrowIcon:String = null; var sparrowIcon:String = null;
var sparrowAnim:String = null; var sparrowAnim:String = null;
if (e.name.startsWith('{note')) {// is actually a note!! if (e.name.startsWith('{note')) {// is actually a note!!
sparrowIcon = "game/notes/default"; sparrowIcon = "game/notes/default";
sparrowAnim = switch(e.name) { sparrowAnim = switch(e.name) {
case '{noteLeft}': case '{noteLeft}':
"purple0"; "purple0";
case '{noteDown}': case '{noteDown}':
"blue0"; "blue0";
case '{noteUp}': case '{noteUp}':
"green0"; "green0";
default: default:
"red0"; "red0";
}; };
e.name = e.name.substring(5, e.name.length - 1); e.name = e.name.substring(5, e.name.length - 1);
} }
var text = new KeybindSetting(100, k * 75, e.name, e.control, sparrowIcon, sparrowAnim); var text = new KeybindSetting(100, k * 75, e.name, e.control, sparrowIcon, sparrowAnim);
if (!isSubState) if (!isSubState)
text.bind1.color = text.bind2.color = FlxColor.BLACK; text.bind1.color = text.bind2.color = FlxColor.BLACK;
alphabets.add(text); alphabets.add(text);
k++; k++;
} }
} }
add(alphabets); add(alphabets);
add(camFollow); add(camFollow);
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
if (settingCam != null) FlxG.cameras.remove(settingCam); if (settingCam != null) FlxG.cameras.remove(settingCam);
instance = null; instance = null;
} }
var skipThisFrame:Bool = true; var skipThisFrame:Bool = true;
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (isSubState) { if (isSubState) {
bg.alpha = lerp(bg.alpha, 0.1, 0.125); bg.alpha = lerp(bg.alpha, 0.1, 0.125);
} else { } else {
if (curSelected < 4) { if (curSelected < 4) {
if (coloredBG.alpha == 0) if (coloredBG.alpha == 0)
coloredBG.color = noteColors[curSelected]; coloredBG.color = noteColors[curSelected];
else else
coloredBG.color = CoolUtil.lerpColor(coloredBG.color, noteColors[curSelected], 0.0625); coloredBG.color = CoolUtil.lerpColor(coloredBG.color, noteColors[curSelected], 0.0625);
coloredBG.alpha = lerp(coloredBG.alpha, 1, 0.0625); coloredBG.alpha = lerp(coloredBG.alpha, 1, 0.0625);
} else } else
coloredBG.alpha = lerp(coloredBG.alpha, 0, 0.0625); coloredBG.alpha = lerp(coloredBG.alpha, 0, 0.0625);
} }
if (canSelect) { if (canSelect) {
changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0)); changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0));
if (controls.BACK) { if (controls.BACK) {
FlxTransitionableState.skipNextTransIn = true; FlxTransitionableState.skipNextTransIn = true;
if (isSubState) if (isSubState)
close(); close();
else else
FlxG.switchState(new OptionsMenu()); FlxG.switchState(new OptionsMenu());
Options.applyKeybinds(); Options.applyKeybinds();
Options.save(); Options.save();
return; return;
} }
if (controls.ACCEPT && !skipThisFrame) { if (controls.ACCEPT && !skipThisFrame) {
if (alphabets.members[curSelected] != null) { if (alphabets.members[curSelected] != null) {
canSelect = false; canSelect = false;
CoolUtil.playMenuSFX(CONFIRM); CoolUtil.playMenuSFX(CONFIRM);
alphabets.members[curSelected].changeKeybind(function() { alphabets.members[curSelected].changeKeybind(function() {
canSelect = true; canSelect = true;
}, function() { }, function() {
canSelect = true; canSelect = true;
}, p2Selected); }, p2Selected);
} }
return; return;
} }
if (controls.LEFT_P || controls.RIGHT_P) { if (controls.LEFT_P || controls.RIGHT_P) {
if (alphabets.members[curSelected] != null) { if (alphabets.members[curSelected] != null) {
CoolUtil.playMenuSFX(SCROLL, 0.7); CoolUtil.playMenuSFX(SCROLL, 0.7);
alphabets.members[curSelected].p2Selected = (p2Selected = !p2Selected); alphabets.members[curSelected].p2Selected = (p2Selected = !p2Selected);
} }
} }
} }
super.update(elapsed); super.update(elapsed);
skipThisFrame = false; skipThisFrame = false;
} }
public function changeSelection(change:Int) { public function changeSelection(change:Int) {
if (change != 0) CoolUtil.playMenuSFX(SCROLL, 0.4); if (change != 0) CoolUtil.playMenuSFX(SCROLL, 0.4);
curSelected = FlxMath.wrap(curSelected + change, 0, alphabets.length-1); curSelected = FlxMath.wrap(curSelected + change, 0, alphabets.length-1);
alphabets.forEach(function(e) { alphabets.forEach(function(e) {
e.alpha = 0.2; e.alpha = 0.2;
}); });
if (alphabets.members[curSelected] != null) { if (alphabets.members[curSelected] != null) {
var alphabet = alphabets.members[curSelected]; var alphabet = alphabets.members[curSelected];
alphabet.p2Selected = p2Selected; alphabet.p2Selected = p2Selected;
alphabet.alpha = 1; alphabet.alpha = 1;
var minH = FlxG.height / 2; var minH = FlxG.height / 2;
var maxH = alphabets.members[alphabets.length-1].y + alphabets.members[alphabets.length-1].height - (FlxG.height / 2); var maxH = alphabets.members[alphabets.length-1].y + alphabets.members[alphabets.length-1].height - (FlxG.height / 2);
if (minH < maxH) if (minH < maxH)
camFollow.setPosition(FlxG.width / 2, FlxMath.bound(alphabet.y + (alphabet.height / 2) - (35), minH, maxH)); camFollow.setPosition(FlxG.width / 2, FlxMath.bound(alphabet.y + (alphabet.height / 2) - (35), minH, maxH));
else else
camFollow.setPosition(FlxG.width / 2, FlxG.height / 2); camFollow.setPosition(FlxG.width / 2, FlxG.height / 2);
} }
} }
} }
+50 -50
View File
@@ -5,67 +5,67 @@ import flixel.math.FlxPoint;
@:allow() @:allow()
class Checkbox extends TextOption { class Checkbox extends TextOption {
public var checkbox:FlxSprite; public var checkbox:FlxSprite;
public var checked:Bool; public var checked:Bool;
public var parent:Dynamic; public var parent:Dynamic;
private function get_selected() { private function get_selected() {
} }
public var optionName:String; public var optionName:String;
private var offsets:Map<String, FlxPoint> = [ private var offsets:Map<String, FlxPoint> = [
"checked" => FlxPoint.get(1, -1), "checked" => FlxPoint.get(1, -1),
"unchecked" => FlxPoint.get(-12, -72), "unchecked" => FlxPoint.get(-12, -72),
"checking" => FlxPoint.get(12, 30) "checking" => FlxPoint.get(12, 30)
]; ];
private var baseCheckboxOffset:FlxPoint = FlxPoint.get(); private var baseCheckboxOffset:FlxPoint = FlxPoint.get();
public function new(text:String, desc:String, optionName:String, ?parent:Dynamic) { public function new(text:String, desc:String, optionName:String, ?parent:Dynamic) {
super(text, desc, null); super(text, desc, null);
if (parent == null) if (parent == null)
parent = Options; parent = Options;
this.parent = parent; this.parent = parent;
checkbox = new FlxSprite(10, -40); checkbox = new FlxSprite(10, -40);
checkbox.frames = Paths.getFrames('menus/options/checkboxThingie'); checkbox.frames = Paths.getFrames('menus/options/checkboxThingie');
checkbox.animation.addByPrefix("checked", "Check Box Selected Static", 24); checkbox.animation.addByPrefix("checked", "Check Box Selected Static", 24);
checkbox.animation.addByPrefix("unchecked", "Check Box unselected", 24); checkbox.animation.addByPrefix("unchecked", "Check Box unselected", 24);
checkbox.animation.addByPrefix("checking", "Check Box selecting animation", 24, false); checkbox.animation.addByPrefix("checking", "Check Box selecting animation", 24, false);
checkbox.antialiasing = true; checkbox.antialiasing = true;
checkbox.scale.set(0.75, 0.75); checkbox.scale.set(0.75, 0.75);
checkbox.updateHitbox(); checkbox.updateHitbox();
add(checkbox); add(checkbox);
baseCheckboxOffset.set(checkbox.offset.x, checkbox.offset.y); baseCheckboxOffset.set(checkbox.offset.x, checkbox.offset.y);
this.optionName = optionName; this.optionName = optionName;
checked = Reflect.field(parent, optionName); checked = Reflect.field(parent, optionName);
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
if (checkbox.animation.curAnim == null || (checkbox.animation.curAnim.finished || (checkbox.animation.curAnim.reversed && checkbox.animation.curAnim.curFrame <= 0))) { if (checkbox.animation.curAnim == null || (checkbox.animation.curAnim.finished || (checkbox.animation.curAnim.reversed && checkbox.animation.curAnim.curFrame <= 0))) {
checkbox.animation.play(checked ? "checked" : "unchecked", true); checkbox.animation.play(checked ? "checked" : "unchecked", true);
} }
super.update(elapsed); super.update(elapsed);
var offset = offsets[checkbox.animation.curAnim.name]; var offset = offsets[checkbox.animation.curAnim.name];
if (offset != null) if (offset != null)
checkbox.offset.set( checkbox.offset.set(
(offset.x * checkbox.scale.x) + baseCheckboxOffset.x, (offset.x * checkbox.scale.x) + baseCheckboxOffset.x,
(offset.y * checkbox.scale.y) + baseCheckboxOffset.y); (offset.y * checkbox.scale.y) + baseCheckboxOffset.y);
} }
public override function onSelect() { public override function onSelect() {
Reflect.setField(parent, optionName, checked = !checked); Reflect.setField(parent, optionName, checked = !checked);
checkbox.animation.play("checking", true, !checked); checkbox.animation.play("checking", true, !checked);
} }
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
for(e in offsets) e.put(); for(e in offsets) e.put();
baseCheckboxOffset.put(); baseCheckboxOffset.put();
} }
} }
+7 -7
View File
@@ -3,13 +3,13 @@ package funkin.options.type;
import funkin.game.HealthIcon; import funkin.game.HealthIcon;
class IconOption extends TextOption { class IconOption extends TextOption {
public var iconSpr:HealthIcon; public var iconSpr:HealthIcon;
public function new(name:String, desc:String, icon:String, callback:Void->Void) { public function new(name:String, desc:String, icon:String, callback:Void->Void) {
super(name, desc, callback); super(name, desc, callback);
iconSpr = new HealthIcon(icon, false); iconSpr = new HealthIcon(icon, false);
iconSpr.setPosition(90 - iconSpr.width, (__text.height - iconSpr.height) / 2); iconSpr.setPosition(90 - iconSpr.width, (__text.height - iconSpr.height) / 2);
add(iconSpr); add(iconSpr);
} }
} }
+15 -15
View File
@@ -5,24 +5,24 @@ import flixel.group.FlxSpriteGroup;
import funkin.options.OptionsScreen; import funkin.options.OptionsScreen;
class OptionType extends FlxSpriteGroup { class OptionType extends FlxSpriteGroup {
public var controls(get, null):Controls; public var controls(get, null):Controls;
public var selected:Bool = false; public var selected:Bool = false;
public var desc:String; public var desc:String;
public function new(desc:String) { public function new(desc:String) {
super(); super();
this.desc = desc; this.desc = desc;
} }
private function get_controls() {return PlayerSettings.solo.controls;} private function get_controls() {return PlayerSettings.solo.controls;}
public function onSelect() { public function onSelect() {
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
alpha = (selected ? 1 : 0.6); alpha = (selected ? 1 : 0.6);
} }
} }
+20 -20
View File
@@ -3,29 +3,29 @@ package funkin.options.type;
import flixel.effects.FlxFlicker; import flixel.effects.FlxFlicker;
class TextOption extends OptionType { class TextOption extends OptionType {
public var selectCallback:Void->Void; public var selectCallback:Void->Void;
private var __text:Alphabet; private var __text:Alphabet;
public var text(get, set):String; public var text(get, set):String;
private function get_text() {return __text.text;} private function get_text() {return __text.text;}
private function set_text(v:String) {return __text.text = v;} private function set_text(v:String) {return __text.text = v;}
public function new(text:String, desc:String, selectCallback:Void->Void) { public function new(text:String, desc:String, selectCallback:Void->Void) {
super(desc); super(desc);
this.selectCallback = selectCallback; this.selectCallback = selectCallback;
add(__text = new Alphabet(100, 20, text, true)); add(__text = new Alphabet(100, 20, text, true));
} }
public override function draw() { public override function draw() {
super.draw(); super.draw();
} }
public override function onSelect() { public override function onSelect() {
super.onSelect(); super.onSelect();
CoolUtil.playMenuSFX(CONFIRM); CoolUtil.playMenuSFX(CONFIRM);
FlxFlicker.flicker(this, 1, Options.flashingMenu ? 0.06 : 0.15, true, false, function(t) { FlxFlicker.flicker(this, 1, Options.flashingMenu ? 0.06 : 0.15, true, false, function(t) {
}); });
selectCallback(); selectCallback();
} }
} }
+10 -10
View File
@@ -4,15 +4,15 @@ package funkin.scripting;
* Simple class for empty scripts or scripts whose language isn't imported yet. * Simple class for empty scripts or scripts whose language isn't imported yet.
*/ */
class DummyScript extends Script { class DummyScript extends Script {
public var variables:Map<String, Dynamic> = []; public var variables:Map<String, Dynamic> = [];
public override function get(v:String) {return variables.get(v);} public override function get(v:String) {return variables.get(v);}
public override function set(v:String, v2:Dynamic) {return variables.set(v, v2);} public override function set(v:String, v2:Dynamic) {return variables.set(v, v2);}
public override function onCall(method:String, parameters:Array<Dynamic>):Dynamic { public override function onCall(method:String, parameters:Array<Dynamic>):Dynamic {
var func = variables.get(method); var func = variables.get(method);
if (Reflect.isFunction(func)) if (Reflect.isFunction(func))
return (parameters != null && parameters.length > 0) ? Reflect.callMethod(null, func, parameters) : func(); return (parameters != null && parameters.length > 0) ? Reflect.callMethod(null, func, parameters) : func();
return null; return null;
} }
} }
+23 -23
View File
@@ -4,35 +4,35 @@ import flixel.FlxState;
import funkin.scripting.events.*; import funkin.scripting.events.*;
class EventManager { class EventManager {
// map doesnt work for that // map doesnt work for that
public static var eventValues:Array<CancellableEvent> = []; public static var eventValues:Array<CancellableEvent> = [];
public static var eventKeys:Array<Class<CancellableEvent>> = []; public static var eventKeys:Array<Class<CancellableEvent>> = [];
public static function get<T:CancellableEvent>(cl:Class<T>):T { public static function get<T:CancellableEvent>(cl:Class<T>):T {
var c:Class<CancellableEvent> = cast cl; var c:Class<CancellableEvent> = cast cl;
var index = eventKeys.indexOf(c); var index = eventKeys.indexOf(c);
if (index < 0) { if (index < 0) {
eventKeys.push(c); eventKeys.push(c);
eventValues.push(Type.createInstance(c, [])); eventValues.push(Type.createInstance(c, []));
return cast eventValues.last(); return cast eventValues.last();
} }
return cast eventValues[index]; return cast eventValues[index];
} }
public static function reset() { public static function reset() {
for(v in eventValues) for(v in eventValues)
v.destroy(); v.destroy();
eventValues = []; eventValues = [];
eventKeys = []; eventKeys = [];
} }
public static function init() { public static function init() {
FlxG.signals.preStateCreate.add(onStateSwitch); FlxG.signals.preStateCreate.add(onStateSwitch);
} }
private static inline function onStateSwitch(newState:FlxState) private static inline function onStateSwitch(newState:FlxState)
reset(); reset();
} }
+91 -91
View File
@@ -9,103 +9,103 @@ import funkin.mods.ModsFolder;
* Class for THE Global Script, aka script that runs in the background at all times. * Class for THE Global Script, aka script that runs in the background at all times.
*/ */
class GlobalScript { class GlobalScript {
public static var script:Script; public static var script:Script;
public static function init() { public static function init() {
#if MOD_SUPPORT #if MOD_SUPPORT
ModsFolder.onModSwitch.add(onModSwitch); ModsFolder.onModSwitch.add(onModSwitch);
#end #end
Conductor.onBeatHit.add(beatHit); Conductor.onBeatHit.add(beatHit);
Conductor.onStepHit.add(stepHit); Conductor.onStepHit.add(stepHit);
FlxG.signals.focusGained.add(function() { FlxG.signals.focusGained.add(function() {
call("focusGained"); call("focusGained");
}); });
FlxG.signals.focusLost.add(function() { FlxG.signals.focusLost.add(function() {
call("focusLost"); call("focusLost");
}); });
FlxG.signals.gameResized.add(function(w:Int, h:Int) { FlxG.signals.gameResized.add(function(w:Int, h:Int) {
call("gameResized", [w, h]); call("gameResized", [w, h]);
}); });
FlxG.signals.postDraw.add(function() { FlxG.signals.postDraw.add(function() {
call("postDraw"); call("postDraw");
}); });
FlxG.signals.postGameReset.add(function() { FlxG.signals.postGameReset.add(function() {
call("postGameReset"); call("postGameReset");
}); });
FlxG.signals.postGameStart.add(function() { FlxG.signals.postGameStart.add(function() {
call("postGameStart"); call("postGameStart");
}); });
FlxG.signals.postStateSwitch.add(function() { FlxG.signals.postStateSwitch.add(function() {
call("postStateSwitch"); call("postStateSwitch");
}); });
FlxG.signals.postUpdate.add(function() { FlxG.signals.postUpdate.add(function() {
call("postUpdate", [FlxG.elapsed]); call("postUpdate", [FlxG.elapsed]);
if (FlxG.keys.justPressed.F5) { if (FlxG.keys.justPressed.F5) {
if (script != null && !(script is DummyScript)) { if (script != null && !(script is DummyScript)) {
Logs.trace('Reloading global script...', WARNING, YELLOW); Logs.trace('Reloading global script...', WARNING, YELLOW);
script.reload(); script.reload();
Logs.trace('Global script successfully reloaded.', WARNING, GREEN); Logs.trace('Global script successfully reloaded.', WARNING, GREEN);
} else { } else {
Logs.trace('Loading global script...', WARNING, YELLOW); Logs.trace('Loading global script...', WARNING, YELLOW);
onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end); onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end);
if (script is DummyScript) if (script is DummyScript)
Logs.trace('Global script not found. Are you sure "data/global.hx" exists?', ERROR, RED); Logs.trace('Global script not found. Are you sure "data/global.hx" exists?', ERROR, RED);
else else
Logs.trace('Global script successfully loaded.', WARNING, GREEN); Logs.trace('Global script successfully loaded.', WARNING, GREEN);
} }
} }
}); });
FlxG.signals.preDraw.add(function() { FlxG.signals.preDraw.add(function() {
call("preDraw"); call("preDraw");
}); });
FlxG.signals.preGameReset.add(function() { FlxG.signals.preGameReset.add(function() {
call("preGameReset"); call("preGameReset");
}); });
FlxG.signals.preGameStart.add(function() { FlxG.signals.preGameStart.add(function() {
call("preGameStart"); call("preGameStart");
}); });
FlxG.signals.preStateCreate.add(function(state:FlxState) { FlxG.signals.preStateCreate.add(function(state:FlxState) {
call("preStateCreate", [state]); call("preStateCreate", [state]);
}); });
FlxG.signals.preStateSwitch.add(function() { FlxG.signals.preStateSwitch.add(function() {
call("preStateSwitch", []); call("preStateSwitch", []);
}); });
FlxG.signals.preUpdate.add(function() { FlxG.signals.preUpdate.add(function() {
call("preUpdate", [FlxG.elapsed]); call("preUpdate", [FlxG.elapsed]);
call("update", [FlxG.elapsed]); call("update", [FlxG.elapsed]);
}); });
onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end); onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end);
} }
public static function event<T:CancellableEvent>(name:String, event:T):T { public static function event<T:CancellableEvent>(name:String, event:T):T {
if (script == null) return event; if (script == null) return event;
script.call(name, [event]); script.call(name, [event]);
return event; return event;
} }
public static function call(name:String, ?args:Array<Dynamic>) { public static function call(name:String, ?args:Array<Dynamic>) {
if (script == null) return; if (script == null) return;
script.call(name, args); script.call(name, args);
} }
public static function onModSwitch(newMod:String) { public static function onModSwitch(newMod:String) {
call("onDestroy"); call("onDestroy");
if (script != null) { if (script != null) {
script.destroy(); script.destroy();
script = null; script = null;
} }
script = Script.create(Paths.script('data/global')); script = Script.create(Paths.script('data/global'));
script.load(); script.load();
} }
public static function beatHit(curBeat:Int) { public static function beatHit(curBeat:Int) {
call("beatHit", [curBeat]); call("beatHit", [curBeat]);
} }
public static function stepHit(curStep:Int) { public static function stepHit(curStep:Int) {
call("stepHit", [curStep]); call("stepHit", [curStep]);
} }
} }
#end #end
+86 -86
View File
@@ -5,112 +5,112 @@ import openfl.Assets;
import hscript.*; import hscript.*;
class HScript extends Script { class HScript extends Script {
public var interp:Interp; public var interp:Interp;
public var expr:Expr; public var expr:Expr;
public override function onCreate(path:String) { public override function onCreate(path:String) {
super.onCreate(path); super.onCreate(path);
interp = new Interp(); interp = new Interp();
var code:String = Assets.getText(path); var code:String = Assets.getText(path);
var parser = new hscript.Parser(); var parser = new hscript.Parser();
parser.allowJSON = parser.allowMetadata = parser.allowTypes = true; parser.allowJSON = parser.allowMetadata = parser.allowTypes = true;
parser.preprocesorValues = Script.getDefaultPreprocessors(); parser.preprocesorValues = Script.getDefaultPreprocessors();
interp.errorHandler = _errorHandler; interp.errorHandler = _errorHandler;
interp.staticVariables = Script.staticVariables; interp.staticVariables = Script.staticVariables;
interp.allowStaticVariables = interp.allowPublicVariables = true; interp.allowStaticVariables = interp.allowPublicVariables = true;
interp.variables.set("trace", Reflect.makeVarArgs((args) -> { interp.variables.set("trace", Reflect.makeVarArgs((args) -> {
var v:String = Std.string(args.shift()); var v:String = Std.string(args.shift());
for (a in args) v += ", " + Std.string(a); for (a in args) v += ", " + Std.string(a);
this.trace(v); this.trace(v);
})); }));
try { try {
expr = parser.parseString(code, fileName); expr = parser.parseString(code, fileName);
} catch(e:Error) { } catch(e:Error) {
_errorHandler(e); _errorHandler(e);
} catch(e) { } catch(e) {
_errorHandler(new Error(ECustom(e.toString()), 0, 0, fileName, 0)); _errorHandler(new Error(ECustom(e.toString()), 0, 0, fileName, 0));
} }
} }
private function _errorHandler(error:Error) { private function _errorHandler(error:Error) {
var fn = '$fileName:${error.line}: '; var fn = '$fileName:${error.line}: ';
var err = error.toString(); var err = error.toString();
if (err.startsWith(fn)) err = err.substr(fn.length); if (err.startsWith(fn)) err = err.substr(fn.length);
Logs.traceColored([ Logs.traceColored([
Logs.logText(fn, GREEN), Logs.logText(fn, GREEN),
Logs.logText(err, RED) Logs.logText(err, RED)
], ERROR); ], ERROR);
} }
public override function setParent(parent:Dynamic) { public override function setParent(parent:Dynamic) {
interp.scriptObject = parent; interp.scriptObject = parent;
} }
public override function onLoad() { public override function onLoad() {
if (expr != null) { if (expr != null) {
interp.execute(expr); interp.execute(expr);
call("new", []); call("new", []);
} }
} }
public override function reload() { public override function reload() {
// save variables // save variables
interp.allowStaticVariables = interp.allowPublicVariables = false; interp.allowStaticVariables = interp.allowPublicVariables = false;
var savedVariables:Map<String, Dynamic> = []; var savedVariables:Map<String, Dynamic> = [];
for(k=>e in interp.variables) { for(k=>e in interp.variables) {
if (!Reflect.isFunction(e)) { if (!Reflect.isFunction(e)) {
savedVariables[k] = e; savedVariables[k] = e;
} }
} }
var oldParent = interp.scriptObject; var oldParent = interp.scriptObject;
onCreate(path); onCreate(path);
for(k=>e in Script.getDefaultVariables(this)) for(k=>e in Script.getDefaultVariables(this))
set(k, e); set(k, e);
load(); load();
setParent(oldParent); setParent(oldParent);
for(k=>e in savedVariables) for(k=>e in savedVariables)
interp.variables.set(k, e); interp.variables.set(k, e);
interp.allowStaticVariables = interp.allowPublicVariables = true; interp.allowStaticVariables = interp.allowPublicVariables = true;
} }
private override function onCall(funcName:String, parameters:Array<Dynamic>):Dynamic { private override function onCall(funcName:String, parameters:Array<Dynamic>):Dynamic {
if (interp == null) return null; if (interp == null) return null;
var func = interp.variables.get(funcName); var func = interp.variables.get(funcName);
if (func != null && Reflect.isFunction(func)) if (func != null && Reflect.isFunction(func))
return (parameters != null && parameters.length > 0) ? Reflect.callMethod(null, func, parameters) : func(); return (parameters != null && parameters.length > 0) ? Reflect.callMethod(null, func, parameters) : func();
return null; return null;
} }
public override function get(val:String):Dynamic { public override function get(val:String):Dynamic {
return interp.variables.get(val); return interp.variables.get(val);
} }
public override function set(val:String, value:Dynamic) { public override function set(val:String, value:Dynamic) {
interp.variables.set(val, value); interp.variables.set(val, value);
} }
public override function trace(v:Dynamic) { public override function trace(v:Dynamic) {
var posInfo = interp.posInfos(); var posInfo = interp.posInfos();
Logs.traceColored([ Logs.traceColored([
Logs.logText('${fileName}:${posInfo.lineNumber}: ', GREEN), Logs.logText('${fileName}:${posInfo.lineNumber}: ', GREEN),
Logs.logText(Std.isOfType(v, String) ? v : Std.string(v)) Logs.logText(Std.isOfType(v, String) ? v : Std.string(v))
], TRACE); ], TRACE);
} }
public override function setPublicMap(map:Map<String, Dynamic>) { public override function setPublicMap(map:Map<String, Dynamic>) {
this.interp.publicVariables = map; this.interp.publicVariables = map;
} }
} }
+3 -3
View File
@@ -1,7 +1,7 @@
package funkin.scripting; package funkin.scripting;
class ModState extends MusicBeatState { class ModState extends MusicBeatState {
public function new(stateName:String) { public function new(stateName:String) {
super(true, stateName); super(true, stateName);
} }
} }
+3 -3
View File
@@ -1,7 +1,7 @@
package funkin.scripting; package funkin.scripting;
class ModSubState extends MusicBeatSubstate { class ModSubState extends MusicBeatSubstate {
public function new(scriptName:String) { public function new(scriptName:String) {
super(true, scriptName); super(true, scriptName);
} }
} }
+69 -69
View File
@@ -8,91 +8,91 @@ import hscript.IHScriptCustomBehaviour;
import flixel.util.FlxDestroyUtil; import flixel.util.FlxDestroyUtil;
class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBehaviour { class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBehaviour {
var thread:#if ALLOW_MULTITHREADING Thread #else Dynamic #end; var thread:#if ALLOW_MULTITHREADING Thread #else Dynamic #end;
/** /**
* Script being ran. * Script being ran.
*/ */
public var script:Script; public var script:Script;
private var __variables:Array<String>; private var __variables:Array<String>;
/** /**
* Return value of the last call. * Return value of the last call.
*/ */
public var returnValue:Dynamic = null; public var returnValue:Dynamic = null;
/** /**
* Whenever the current call has ended. * Whenever the current call has ended.
*/ */
public var callEnded:Bool = true; public var callEnded:Bool = true;
public function new(path:String, ?parentScript:Script) { public function new(path:String, ?parentScript:Script) {
script = Script.create(path); script = Script.create(path);
if (parentScript != null) { if (parentScript != null) {
if (script is HScript && parentScript is HScript) { if (script is HScript && parentScript is HScript) {
var hscript = cast(script, HScript); var hscript = cast(script, HScript);
var parentHScript = cast(parentScript, HScript); var parentHScript = cast(parentScript, HScript);
hscript.interp.variables = parentHScript.interp.variables; hscript.interp.variables = parentHScript.interp.variables;
hscript.interp.publicVariables = parentHScript.interp.publicVariables; hscript.interp.publicVariables = parentHScript.interp.publicVariables;
hscript.interp.staticVariables = parentHScript.interp.staticVariables; hscript.interp.staticVariables = parentHScript.interp.staticVariables;
script.setParent(parentHScript.interp.scriptObject); script.setParent(parentHScript.interp.scriptObject);
} }
} }
script.load(); script.load();
#if ALLOW_MULTITHREADING #if ALLOW_MULTITHREADING
thread = Thread.createWithEventLoop(function() { thread = Thread.createWithEventLoop(function() {
// Prevent the thread from being auto deleted // Prevent the thread from being auto deleted
Thread.current().events.promise(); Thread.current().events.promise();
}); });
#end #end
__variables = Type.getInstanceFields(Type.getClass(this)); __variables = Type.getInstanceFields(Type.getClass(this));
} }
public inline function hget(name:String):Dynamic public inline function hget(name:String):Dynamic
return __variables.contains(name) ? Reflect.getProperty(this, name) : script.get(name); return __variables.contains(name) ? Reflect.getProperty(this, name) : script.get(name);
public inline function hset(name:String, val:Dynamic):Dynamic { public inline function hset(name:String, val:Dynamic):Dynamic {
if (__variables.contains(name)) if (__variables.contains(name))
Reflect.setProperty(this, name, val); Reflect.setProperty(this, name, val);
else else
script.set(name, val); script.set(name, val);
return val; return val;
} }
public function call(func:String, args:Array<Dynamic>) { public function call(func:String, args:Array<Dynamic>) {
#if ALLOW_MULTITHREADING #if ALLOW_MULTITHREADING
thread.events.run(function() { thread.events.run(function() {
callEnded = false; callEnded = false;
returnValue = script.call(func, args); returnValue = script.call(func, args);
callEnded = true; callEnded = true;
}); });
#else #else
returnValue = script.call(func, args); returnValue = script.call(func, args);
callEnded = true; callEnded = true;
#end #end
} }
public function destroy() { public function destroy() {
if (script != null) { if (script != null) {
script.call("onDestroy"); script.call("onDestroy");
script.destroy(); script.destroy();
} }
#if ALLOW_MULTITHREADING #if ALLOW_MULTITHREADING
if (thread != null) { if (thread != null) {
thread.events.runPromised(function() { thread.events.runPromised(function() {
// close the thing // close the thing
}); });
} }
#end #end
} }
} }
+230 -230
View File
@@ -8,266 +8,266 @@ import haxe.io.Path;
* Class used for scripting. * Class used for scripting.
*/ */
class Script extends FlxBasic implements IFlxDestroyable { class Script extends FlxBasic implements IFlxDestroyable {
/** /**
* Use "static var thing = true;" in hscript to use those!! * Use "static var thing = true;" in hscript to use those!!
* are reset every mod switch so once you're done with them make sure to make them null!! * are reset every mod switch so once you're done with them make sure to make them null!!
*/ */
public static var staticVariables:Map<String, Dynamic> = []; public static var staticVariables:Map<String, Dynamic> = [];
public static function getDefaultVariables(?script:Script):Map<String, Dynamic> { public static function getDefaultVariables(?script:Script):Map<String, Dynamic> {
return [ return [
// Haxe related stuff // Haxe related stuff
"Std" => Std, "Std" => Std,
"Math" => Math, "Math" => Math,
"StringTools" => StringTools, "StringTools" => StringTools,
"Json" => haxe.Json, "Json" => haxe.Json,
// OpenFL & Lime related stuff // OpenFL & Lime related stuff
"Assets" => openfl.utils.Assets, "Assets" => openfl.utils.Assets,
"Application" => lime.app.Application, "Application" => lime.app.Application,
"window" => lime.app.Application.current.window, "window" => lime.app.Application.current.window,
// Flixel related stuff // Flixel related stuff
"FlxG" => flixel.FlxG, "FlxG" => flixel.FlxG,
"FlxSprite" => flixel.FlxSprite, "FlxSprite" => flixel.FlxSprite,
"FlxBasic" => flixel.FlxBasic, "FlxBasic" => flixel.FlxBasic,
"FlxCamera" => flixel.FlxCamera, "FlxCamera" => flixel.FlxCamera,
"state" => flixel.FlxG.state, "state" => flixel.FlxG.state,
"FlxEase" => flixel.tweens.FlxEase, "FlxEase" => flixel.tweens.FlxEase,
"FlxTween" => flixel.tweens.FlxTween, "FlxTween" => flixel.tweens.FlxTween,
"FlxSound" => flixel.system.FlxSound, "FlxSound" => flixel.system.FlxSound,
"FlxAssets" => flixel.system.FlxAssets, "FlxAssets" => flixel.system.FlxAssets,
"FlxMath" => flixel.math.FlxMath, "FlxMath" => flixel.math.FlxMath,
"FlxGroup" => flixel.group.FlxGroup, "FlxGroup" => flixel.group.FlxGroup,
"FlxTypedGroup" => flixel.group.FlxGroup.FlxTypedGroup, "FlxTypedGroup" => flixel.group.FlxGroup.FlxTypedGroup,
"FlxSpriteGroup" => flixel.group.FlxSpriteGroup, "FlxSpriteGroup" => flixel.group.FlxSpriteGroup,
"FlxTypeText" => flixel.addons.text.FlxTypeText, "FlxTypeText" => flixel.addons.text.FlxTypeText,
"FlxText" => flixel.text.FlxText, "FlxText" => flixel.text.FlxText,
"FlxTimer" => flixel.util.FlxTimer, "FlxTimer" => flixel.util.FlxTimer,
"FlxPoint" => CoolUtil.getMacroAbstractClass("flixel.math.FlxPoint"), "FlxPoint" => CoolUtil.getMacroAbstractClass("flixel.math.FlxPoint"),
"FlxAxes" => CoolUtil.getMacroAbstractClass("flixel.util.FlxAxes"), "FlxAxes" => CoolUtil.getMacroAbstractClass("flixel.util.FlxAxes"),
"FlxColor" => CoolUtil.getMacroAbstractClass("flixel.util.FlxColor"), "FlxColor" => CoolUtil.getMacroAbstractClass("flixel.util.FlxColor"),
// Engine related stuff // Engine related stuff
"engine" => { "engine" => {
commit: funkin.macros.GitCommitMacro.commitNumber, commit: funkin.macros.GitCommitMacro.commitNumber,
build: 2675, // 2675 being the last build num before it was removed build: 2675, // 2675 being the last build num before it was removed
name: "Codename Engine" name: "Codename Engine"
}, },
"ModState" => funkin.scripting.ModState, "ModState" => funkin.scripting.ModState,
"ModSubState" => funkin.scripting.ModSubState, "ModSubState" => funkin.scripting.ModSubState,
"PlayState" => funkin.game.PlayState, "PlayState" => funkin.game.PlayState,
"GameOverSubstate" => funkin.game.GameOverSubstate, "GameOverSubstate" => funkin.game.GameOverSubstate,
"HealthIcon" => funkin.game.HealthIcon, "HealthIcon" => funkin.game.HealthIcon,
"HudCamera" => funkin.game.HudCamera, "HudCamera" => funkin.game.HudCamera,
"Note" => funkin.game.Note, "Note" => funkin.game.Note,
"Strum" => funkin.game.Strum, "Strum" => funkin.game.Strum,
"StrumLine" => funkin.game.StrumLine, "StrumLine" => funkin.game.StrumLine,
"Character" => funkin.game.Character, "Character" => funkin.game.Character,
"Boyfriend" => funkin.game.Character, // for compatibility "Boyfriend" => funkin.game.Character, // for compatibility
"PauseSubstate" => funkin.menus.PauseSubState, "PauseSubstate" => funkin.menus.PauseSubState,
"FreeplayState" => funkin.menus.FreeplayState, "FreeplayState" => funkin.menus.FreeplayState,
"MainMenuState" => funkin.menus.MainMenuState, "MainMenuState" => funkin.menus.MainMenuState,
"PauseSubState" => funkin.menus.PauseSubState, "PauseSubState" => funkin.menus.PauseSubState,
"StoryMenuState" => funkin.menus.StoryMenuState, "StoryMenuState" => funkin.menus.StoryMenuState,
"TitleState" => funkin.menus.TitleState, "TitleState" => funkin.menus.TitleState,
"Options" => funkin.options.Options, "Options" => funkin.options.Options,
"Paths" => funkin.system.Paths, "Paths" => funkin.system.Paths,
"Conductor" => funkin.system.Conductor, "Conductor" => funkin.system.Conductor,
"FunkinShader" => funkin.shaders.FunkinShader, "FunkinShader" => funkin.shaders.FunkinShader,
"CustomShader" => funkin.shaders.CustomShader, "CustomShader" => funkin.shaders.CustomShader,
"FunkinText" => funkin.ui.FunkinText, "FunkinText" => funkin.ui.FunkinText,
"Alphabet" => funkin.ui.Alphabet, "Alphabet" => funkin.ui.Alphabet,
"CoolUtil" => funkin.utils.CoolUtil, "CoolUtil" => funkin.utils.CoolUtil,
"IniUtil" => funkin.utils.IniUtil, "IniUtil" => funkin.utils.IniUtil,
"XMLUtil" => funkin.utils.XMLUtil, "XMLUtil" => funkin.utils.XMLUtil,
#if sys "ZipUtil" => funkin.utils.ZipUtil, #end #if sys "ZipUtil" => funkin.utils.ZipUtil, #end
"MarkdownUtil" => funkin.utils.MarkdownUtil, "MarkdownUtil" => funkin.utils.MarkdownUtil,
"EngineUtil" => funkin.utils.EngineUtil, "EngineUtil" => funkin.utils.EngineUtil,
]; ];
} }
public static function getDefaultPreprocessors():Map<String, Dynamic> { public static function getDefaultPreprocessors():Map<String, Dynamic> {
return [ return [
"CODENAME_ENGINE" => true, "CODENAME_ENGINE" => true,
"CODENAME_VER" => Application.current.meta.get('version'), "CODENAME_VER" => Application.current.meta.get('version'),
"CODENAME_BUILD" => 2675, "CODENAME_BUILD" => 2675,
"CODENAME_COMMIT" => funkin.macros.GitCommitMacro.commitNumber, "CODENAME_COMMIT" => funkin.macros.GitCommitMacro.commitNumber,
"desktop" => #if desktop true #else false #end, "desktop" => #if desktop true #else false #end,
"windows" => #if windows true #else false #end, "windows" => #if windows true #else false #end,
"hl" => #if hl true #else false #end, "hl" => #if hl true #else false #end,
"neko" => #if neko true #else false #end, "neko" => #if neko true #else false #end,
"linux" => #if linux true #else false #end, "linux" => #if linux true #else false #end,
"mac" => #if mac true #else false #end, "mac" => #if mac true #else false #end,
"macos" => #if macos true #else false #end, "macos" => #if macos true #else false #end,
"android" => #if android true #else false #end, "android" => #if android true #else false #end,
"web" => #if web true #else false #end, "web" => #if web true #else false #end,
"debug" => #if debug true #else false #end, "debug" => #if debug true #else false #end,
"release" => #if release true #else false #end, "release" => #if release true #else false #end,
"final" => #if final true #else false #end, "final" => #if final true #else false #end,
"MOD_SUPPORT" => #if MOD_SUPPORT true #else false #end, "MOD_SUPPORT" => #if MOD_SUPPORT true #else false #end,
"GLOBAL_SCRIPT" => #if GLOBAL_SCRIPT true #else false #end, "GLOBAL_SCRIPT" => #if GLOBAL_SCRIPT true #else false #end,
"SOFTCODED_STATES" => #if SOFTCODED_STATES true #else false #end, "SOFTCODED_STATES" => #if SOFTCODED_STATES true #else false #end,
"USE_SOURCE_ASSETS" => #if USE_SOURCE_ASSETS true #else false #end, "USE_SOURCE_ASSETS" => #if USE_SOURCE_ASSETS true #else false #end,
"USE_ADAPTED_ASSETS" => #if USE_ADAPTED_ASSETS true #else false #end, "USE_ADAPTED_ASSETS" => #if USE_ADAPTED_ASSETS true #else false #end,
]; ];
} }
/** /**
* All available script extensions * All available script extensions
*/ */
public static var scriptExtensions:Array<String> = [ public static var scriptExtensions:Array<String> = [
"hx", "hscript", "hsc", "hxs", "lua" /** ACTUALLY NOT SUPPORTED, ONLY FOR THE MESSAGE **/ "hx", "hscript", "hsc", "hxs", "lua" /** ACTUALLY NOT SUPPORTED, ONLY FOR THE MESSAGE **/
]; ];
/** /**
* Currently executing script. * Currently executing script.
*/ */
public static var curScript:Script = null; public static var curScript:Script = null;
/** /**
* Script name (with extension) * Script name (with extension)
*/ */
public var fileName:String; public var fileName:String;
/** /**
* Path to the script. * Path to the script.
*/ */
public var path:String = null; public var path:String = null;
/** /**
* Creates a script from the specified asset path. The language is automatically determined. * Creates a script from the specified asset path. The language is automatically determined.
* @param path Path in assets * @param path Path in assets
*/ */
public static function create(path:String):Script { public static function create(path:String):Script {
if (Assets.exists(path)) { if (Assets.exists(path)) {
return switch(Path.extension(path).toLowerCase()) { return switch(Path.extension(path).toLowerCase()) {
case "hx" | "hscript" | "hsc" | "hxs": case "hx" | "hscript" | "hsc" | "hxs":
new HScript(path); new HScript(path);
case "lua": case "lua":
Logs.trace("Lua is not supported in this engine. Use HScript instead.", ERROR); Logs.trace("Lua is not supported in this engine. Use HScript instead.", ERROR);
new DummyScript(path); new DummyScript(path);
default: default:
new DummyScript(path); new DummyScript(path);
} }
} }
return new DummyScript(path); return new DummyScript(path);
} }
/** /**
* Creates a new instance of the script class. * Creates a new instance of the script class.
* @param path * @param path
*/ */
public function new(path:String) { public function new(path:String) {
super(); super();
fileName = Path.withoutDirectory(path); fileName = Path.withoutDirectory(path);
this.path = path; this.path = path;
onCreate(path); onCreate(path);
for(k=>e in getDefaultVariables(this)) { for(k=>e in getDefaultVariables(this)) {
set(k, e); set(k, e);
} }
} }
/** /**
* Loads the script * Loads the script
*/ */
public function load() { public function load() {
var oldScript = curScript; var oldScript = curScript;
curScript = this; curScript = this;
onLoad(); onLoad();
curScript = oldScript; curScript = oldScript;
} }
/** /**
* HSCRIPT ONLY FOR NOW * HSCRIPT ONLY FOR NOW
* Sets the "public" variables map for ScriptPack * Sets the "public" variables map for ScriptPack
*/ */
public function setPublicMap(map:Map<String, Dynamic>) { public function setPublicMap(map:Map<String, Dynamic>) {
} }
/** /**
* Hot-reloads the script, if possible * Hot-reloads the script, if possible
*/ */
public function reload() { public function reload() {
} }
/** /**
* Traces something as this script. * Traces something as this script.
*/ */
public function trace(v:Dynamic) { public function trace(v:Dynamic) {
Logs.traceColored([ Logs.traceColored([
Logs.logText('${fileName}: ', GREEN), Logs.logText('${fileName}: ', GREEN),
Logs.logText(Std.string(v)) Logs.logText(Std.string(v))
], TRACE); ], TRACE);
} }
/** /**
* Calls the function `func` defined in the script. * Calls the function `func` defined in the script.
* @param func Name of the function * @param func Name of the function
* @param parameters (Optional) Parameters of the function. * @param parameters (Optional) Parameters of the function.
* @return Result (if void, then null) * @return Result (if void, then null)
*/ */
public function call(func:String, ?parameters:Array<Dynamic>):Dynamic { public function call(func:String, ?parameters:Array<Dynamic>):Dynamic {
var oldScript = curScript; var oldScript = curScript;
curScript = this; curScript = this;
var result = onCall(func, parameters == null ? [] : parameters); var result = onCall(func, parameters == null ? [] : parameters);
curScript = oldScript; curScript = oldScript;
return result; return result;
} }
/** /**
* Sets a script's parent object so that its properties can be accessed easily. Ex: Passing `PlayState.instance` will allow `boyfriend` to be typed instead of `PlayState.instance.boyfriend`. * Sets a script's parent object so that its properties can be accessed easily. Ex: Passing `PlayState.instance` will allow `boyfriend` to be typed instead of `PlayState.instance.boyfriend`.
* @param variable Parent variable. * @param variable Parent variable.
*/ */
public function setParent(variable:Dynamic) {} public function setParent(variable:Dynamic) {}
/** /**
* Gets the variable `variable` from the script's variables. * Gets the variable `variable` from the script's variables.
* @param variable Name of the variable. * @param variable Name of the variable.
* @return Variable (or null if it doesn't exists) * @return Variable (or null if it doesn't exists)
*/ */
public function get(variable:String):Dynamic {return null;} public function get(variable:String):Dynamic {return null;}
/** /**
* Gets the variable `variable` from the script's variables. * Gets the variable `variable` from the script's variables.
* @param variable Name of the variable. * @param variable Name of the variable.
* @return Variable (or null if it doesn't exists) * @return Variable (or null if it doesn't exists)
*/ */
public function set(variable:String, value:Dynamic):Void {} public function set(variable:String, value:Dynamic):Void {}
/** /**
* Shows an error from this script. * Shows an error from this script.
* @param text Text of the error (ex: Null Object Reference). * @param text Text of the error (ex: Null Object Reference).
* @param additionalInfo Additional information you could provide. * @param additionalInfo Additional information you could provide.
*/ */
public function error(text:String, ?additionalInfo:Dynamic):Void { public function error(text:String, ?additionalInfo:Dynamic):Void {
Logs.traceColored([ Logs.traceColored([
Logs.logText(fileName, RED), Logs.logText(fileName, RED),
Logs.logText(text) Logs.logText(text)
], ERROR); ], ERROR);
} }
/** /**
* PRIVATE HANDLERS - DO NOT TOUCH * PRIVATE HANDLERS - DO NOT TOUCH
*/ */
private function onCall(func:String, parameters:Array<Dynamic>):Dynamic { private function onCall(func:String, parameters:Array<Dynamic>):Dynamic {
return null; return null;
} }
public function onCreate(path:String) {} public function onCreate(path:String) {}
public function onLoad() {} public function onLoad() {}
public function onDestroy() {}; public function onDestroy() {};
public override function destroy() { public override function destroy() {
super.destroy(); super.destroy();
onDestroy(); onDestroy();
} }
} }
+98 -98
View File
@@ -4,117 +4,117 @@ import funkin.scripting.events.CancellableEvent;
@:access(CancellableEvent) @:access(CancellableEvent)
class ScriptPack extends Script { class ScriptPack extends Script {
public var scripts:Array<Script> = []; public var scripts:Array<Script> = [];
public var additionalDefaultVariables:Map<String, Dynamic> = []; public var additionalDefaultVariables:Map<String, Dynamic> = [];
public var publicVariables:Map<String, Dynamic> = []; public var publicVariables:Map<String, Dynamic> = [];
public var parent:Dynamic = null; public var parent:Dynamic = null;
public override function load() { public override function load() {
for(e in scripts) { for(e in scripts) {
e.load(); e.load();
} }
} }
public function contains(path:String) { public function contains(path:String) {
for(e in scripts) for(e in scripts)
if (e.path == path) if (e.path == path)
return true; return true;
return false; return false;
} }
public function new(name:String) { public function new(name:String) {
additionalDefaultVariables["importScript"] = importScript; additionalDefaultVariables["importScript"] = importScript;
super(name); super(name);
} }
public function getByPath(name:String) { public function getByPath(name:String) {
for(s in scripts) for(s in scripts)
if (s.path == name) if (s.path == name)
return s; return s;
return null; return null;
} }
public function getByName(name:String) { public function getByName(name:String) {
for(s in scripts) for(s in scripts)
if (s.fileName == name) if (s.fileName == name)
return s; return s;
return null; return null;
} }
public function importScript(path:String):Script { public function importScript(path:String):Script {
var script = Script.create(Paths.script(path)); var script = Script.create(Paths.script(path));
if (script is DummyScript) { if (script is DummyScript) {
throw 'Script at ${path} does not exist.'; throw 'Script at ${path} does not exist.';
return null; return null;
} }
add(script); add(script);
script.load(); script.load();
return script; return script;
} }
public override function call(func:String, ?parameters:Array<Dynamic>):Dynamic { public override function call(func:String, ?parameters:Array<Dynamic>):Dynamic {
for(e in scripts) for(e in scripts)
e.call(func, parameters); e.call(func, parameters);
return null; return null;
} }
/** /**
* Sends an event to every single script, and returns the event. * Sends an event to every single script, and returns the event.
* @param func Function to call * @param func Function to call
* @param event Event (will be the first parameter of the function) * @param event Event (will be the first parameter of the function)
* @return (modified by scripts) * @return (modified by scripts)
*/ */
public function event<T:CancellableEvent>(func:String, event:T):T { public function event<T:CancellableEvent>(func:String, event:T):T {
for(e in scripts) { for(e in scripts) {
e.call(func, [event]); e.call(func, [event]);
@:privateAccess @:privateAccess
if (event.cancelled && !event.__continueCalls) break; if (event.cancelled && !event.__continueCalls) break;
} }
return event; return event;
} }
public override function get(val:String):Dynamic { public override function get(val:String):Dynamic {
for(e in scripts) { for(e in scripts) {
var v = e.get(val); var v = e.get(val);
if (v != null) return v; if (v != null) return v;
} }
return null; return null;
} }
public override function reload() { public override function reload() {
for(e in scripts) e.reload(); for(e in scripts) e.reload();
} }
public override function set(val:String, value:Dynamic) { public override function set(val:String, value:Dynamic) {
for(e in scripts) e.set(val, value); for(e in scripts) e.set(val, value);
} }
public override function setParent(parent:Dynamic) { public override function setParent(parent:Dynamic) {
this.parent = parent; this.parent = parent;
for(e in scripts) e.setParent(parent); for(e in scripts) e.setParent(parent);
} }
public override function onDestroy() { public override function onDestroy() {
for(e in scripts) e.destroy(); for(e in scripts) e.destroy();
} }
public override function onCreate(path:String) {} public override function onCreate(path:String) {}
public function add(script:Script) { public function add(script:Script) {
scripts.push(script); scripts.push(script);
__configureNewScript(script); __configureNewScript(script);
} }
public function remove(script:Script) { public function remove(script:Script) {
scripts.remove(script); scripts.remove(script);
} }
public function insert(pos:Int, script:Script) { public function insert(pos:Int, script:Script) {
scripts.insert(pos, script); scripts.insert(pos, script);
__configureNewScript(script); __configureNewScript(script);
} }
private function __configureNewScript(script:Script) { private function __configureNewScript(script:Script) {
if (parent != null) script.setParent(parent); if (parent != null) script.setParent(parent);
script.setPublicMap(publicVariables); script.setPublicMap(publicVariables);
for(k=>e in additionalDefaultVariables) script.set(k, e); for(k=>e in additionalDefaultVariables) script.set(k, e);
} }
} }
+12 -12
View File
@@ -4,18 +4,18 @@ import funkin.game.StrumLine;
import flixel.math.FlxPoint; import flixel.math.FlxPoint;
class CamMoveEvent extends CancellableEvent { class CamMoveEvent extends CancellableEvent {
/** /**
* Final camera position. * Final camera position.
*/ */
public var position:FlxPoint; public var position:FlxPoint;
/** /**
* Currently focused strumline. * Currently focused strumline.
*/ */
public var strumLine:StrumLine; public var strumLine:StrumLine;
/** /**
* Number of focused characters * Number of focused characters
*/ */
public var focusedCharacters:Int; public var focusedCharacters:Int;
} }
@@ -5,52 +5,52 @@ import flixel.util.FlxDestroyUtil.IFlxDestroyable;
@:allow(ScriptPack) @:allow(ScriptPack)
@:autoBuild(funkin.macros.EventMacro.build()) @:autoBuild(funkin.macros.EventMacro.build())
class CancellableEvent implements IFlxDestroyable { class CancellableEvent implements IFlxDestroyable {
@:dox(hide) public var cancelled:Bool = false; @:dox(hide) public var cancelled:Bool = false;
@:dox(hide) private var __continueCalls:Bool = true; @:dox(hide) private var __continueCalls:Bool = true;
/** /**
* Additional data if used in scripts * Additional data if used in scripts
*/ */
public var data:Dynamic = {}; public var data:Dynamic = {};
/** /**
* Prevents default action from occurring. * Prevents default action from occurring.
* @param c Whenever the scripts following this one should be called or not. (Defaults to `true`) * @param c Whenever the scripts following this one should be called or not. (Defaults to `true`)
*/ */
public function preventDefault(c:Bool = false) { public function preventDefault(c:Bool = false) {
cancelled = true; cancelled = true;
__continueCalls = c; __continueCalls = c;
} }
@:dox(hide) @:dox(hide)
public function cancel(c:Bool = true) {preventDefault(c);} public function cancel(c:Bool = true) {preventDefault(c);}
/** /**
* Creates a new cancellable event. * Creates a new cancellable event.
* This allows scripts to call `cancel()` to cancel the event. * This allows scripts to call `cancel()` to cancel the event.
*/ */
public function new() {} public function new() {}
public function recycleBase() { public function recycleBase() {
data = {}; data = {};
cancelled = false; cancelled = false;
__continueCalls = true; __continueCalls = true;
} }
/** /**
* Returns a string representation of the event, in this format: * Returns a string representation of the event, in this format:
* `[CancellableEvent]` * `[CancellableEvent]`
* `[CancellableEvent (Cancelled)]` * `[CancellableEvent (Cancelled)]`
* @return String * @return String
*/ */
public function toString():String { public function toString():String {
var fields = Reflect.fields(this); var fields = Reflect.fields(this);
var claName = Type.getClassName(Type.getClass(this)).split("."); var claName = Type.getClassName(Type.getClass(this)).split(".");
var rep = '[${claName[claName.length-1]}${cancelled ? " (Cancelled)" : ""}]'; var rep = '[${claName[claName.length-1]}${cancelled ? " (Cancelled)" : ""}]';
return rep; return rep;
} }
public function destroy() { public function destroy() {
data = null; data = null;
} }
} }
@@ -4,42 +4,42 @@ import flixel.tweens.FlxTween;
import flixel.system.FlxSound; import flixel.system.FlxSound;
class CountdownEvent extends CancellableEvent { class CountdownEvent extends CancellableEvent {
/** /**
* At which count the countdown is. Normally goes 0-1-2-3-4 unless `PlayState.instance.introLength` is changed. * At which count the countdown is. Normally goes 0-1-2-3-4 unless `PlayState.instance.introLength` is changed.
*/ */
public var swagCounter:Int; public var swagCounter:Int;
/** /**
* Volume at which the intro countdown sound will play. * Volume at which the intro countdown sound will play.
*/ */
public var volume:Float; public var volume:Float;
/** /**
* Path of the intro sound that'll be played. * Path of the intro sound that'll be played.
*/ */
public var soundPath:String; public var soundPath:String;
/** /**
* Path to the sprite path that'll be shown. * Path to the sprite path that'll be shown.
*/ */
public var spritePath:String; public var spritePath:String;
/** /**
* Scale of the sprite. * Scale of the sprite.
*/ */
public var scale:Float; public var scale:Float;
/** /**
* Whenever antialiasing is enabled or not. * Whenever antialiasing is enabled or not.
*/ */
public var antialiasing:Bool; public var antialiasing:Bool;
/** /**
* Created sprite, only available in `onPostCountdown` * Created sprite, only available in `onPostCountdown`
*/ */
public var sprite:FlxSprite; public var sprite:FlxSprite;
/** /**
* Created tween for the sprite, only available in `onPostCountdown` * Created tween for the sprite, only available in `onPostCountdown`
*/ */
public var spriteTween:FlxTween; public var spriteTween:FlxTween;
/** /**
* Created sound, only available in `onPostCountdown` * Created sound, only available in `onPostCountdown`
*/ */
public var sound:FlxSound; public var sound:FlxSound;
} }
+1 -1
View File
@@ -1,5 +1,5 @@
package funkin.scripting.events; package funkin.scripting.events;
class DanceEvent extends CancellableEvent { class DanceEvent extends CancellableEvent {
public var danced:Bool; public var danced:Bool;
} }
@@ -3,32 +3,32 @@ package funkin.scripting.events;
import funkin.scripting.events.PlayAnimEvent.PlayAnimContext; import funkin.scripting.events.PlayAnimEvent.PlayAnimContext;
class DirectionAnimEvent extends CancellableEvent { class DirectionAnimEvent extends CancellableEvent {
/** /**
Default animation that will be played Default animation that will be played
**/ **/
public var animName:String; public var animName:String;
/** /**
In which direction the animation will be played In which direction the animation will be played
**/ **/
public var direction:Int; public var direction:Int;
/** /**
The suffix of the animation (ex: "-alt") - Defaults to "" The suffix of the animation (ex: "-alt") - Defaults to ""
**/ **/
public var suffix:String; public var suffix:String;
/** /**
Context of the animation. Is either equal to `SING` or `MISS`. Context of the animation. Is either equal to `SING` or `MISS`.
**/ **/
public var context:PlayAnimContext; public var context:PlayAnimContext;
/** /**
Whenever the animation will play reversed or not. Whenever the animation will play reversed or not.
**/ **/
public var reversed:Bool; public var reversed:Bool;
/** /**
At what frame the animation will start playing At what frame the animation will start playing
**/ **/
public var frame:Int; public var frame:Int;
/** /**
Whenever the animation will play reversed or not. Whenever the animation will play reversed or not.
**/ **/
public var force:Bool = true; public var force:Bool = true;
} }
@@ -5,8 +5,8 @@ import discord_rpc.DiscordRpc.DiscordPresenceOptions;
#end #end
class DiscordPresenceUpdateEvent extends CancellableEvent { class DiscordPresenceUpdateEvent extends CancellableEvent {
/** /**
* Object containing all of the data for the presence. Can be altered. * Object containing all of the data for the presence. Can be altered.
*/ */
public var presenceData:#if DISCORD_RPC DiscordPresenceOptions #else Dynamic #end; public var presenceData:#if DISCORD_RPC DiscordPresenceOptions #else Dynamic #end;
} }
@@ -1,20 +1,20 @@
package funkin.scripting.events; package funkin.scripting.events;
class FreeplaySongSelectEvent extends CancellableEvent { class FreeplaySongSelectEvent extends CancellableEvent {
/** /**
* Song name that is about to be played * Song name that is about to be played
*/ */
public var song:String; public var song:String;
/** /**
* Difficulty name * Difficulty name
*/ */
public var difficulty:String; public var difficulty:String;
/** /**
* Whenever opponent mode is enabled or not. * Whenever opponent mode is enabled or not.
*/ */
public var opponentMode:Bool; public var opponentMode:Bool;
/** /**
* Whenever coop mode is enabled. * Whenever coop mode is enabled.
*/ */
public var coopMode:Bool; public var coopMode:Bool;
} }
@@ -3,31 +3,31 @@ package funkin.scripting.events;
import funkin.game.StrumLine; import funkin.game.StrumLine;
class InputSystemEvent extends CancellableEvent { class InputSystemEvent extends CancellableEvent {
/** /**
* Array containing whenever a specific control is pressed or not. * Array containing whenever a specific control is pressed or not.
* For example, `pressed[0]` will return whenever the left strum was pressed. * For example, `pressed[0]` will return whenever the left strum was pressed.
*/ */
public var pressed:Array<Bool>; public var pressed:Array<Bool>;
/** /**
* Array containing whenever a specific control was pressed (not hold) this frame or not. * Array containing whenever a specific control was pressed (not hold) this frame or not.
* For example, `justPressed[0]` will return whenever the left strum was just pressed. * For example, `justPressed[0]` will return whenever the left strum was just pressed.
*/ */
public var justPressed:Array<Bool>; public var justPressed:Array<Bool>;
/** /**
* Array containing whenever a specific control was released this frame or not. * Array containing whenever a specific control was released this frame or not.
* For example, `justReleased[0]` will return whenever the left strum was just released. * For example, `justReleased[0]` will return whenever the left strum was just released.
*/ */
public var justReleased:Array<Bool>; public var justReleased:Array<Bool>;
/** /**
* Strumline which input is being processed. * Strumline which input is being processed.
*/ */
public var strumLine:StrumLine; public var strumLine:StrumLine;
/** /**
* ID of the Strumline. * ID of the Strumline.
*/ */
public var strumLineID:Int; public var strumLineID:Int;
} }
@@ -1,23 +1,23 @@
package funkin.scripting.events; package funkin.scripting.events;
class MenuChangeEvent extends CancellableEvent { class MenuChangeEvent extends CancellableEvent {
/** /**
* Value before the change * Value before the change
*/ */
public var oldValue:Int; public var oldValue:Int;
/** /**
* Value after the change * Value after the change
*/ */
public var value:Int; public var value:Int;
/** /**
* Amount of change * Amount of change
*/ */
public var change:Int; public var change:Int;
/** /**
* Whenever the menu SFX should be played. * Whenever the menu SFX should be played.
*/ */
public var playMenuSFX:Bool = true; public var playMenuSFX:Bool = true;
} }
+4 -4
View File
@@ -1,8 +1,8 @@
package funkin.scripting.events; package funkin.scripting.events;
class NameEvent extends CancellableEvent { class NameEvent extends CancellableEvent {
/** /**
* Name * Name
*/ */
public var name:String; public var name:String;
} }
@@ -3,48 +3,48 @@ package funkin.scripting.events;
import funkin.game.Note; import funkin.game.Note;
class NoteCreationEvent extends CancellableEvent { class NoteCreationEvent extends CancellableEvent {
/** /**
* Note that is being created * Note that is being created
*/ */
public var note:Note; public var note:Note;
/** /**
* ID of the strum (from 0 to 3) * ID of the strum (from 0 to 3)
*/ */
public var strumID:Int; public var strumID:Int;
/** /**
* Note Type (ex: "My Super Cool Note", or "Mine") * Note Type (ex: "My Super Cool Note", or "Mine")
*/ */
public var noteType:String; public var noteType:String;
/** /**
* ID of the note type. * ID of the note type.
*/ */
public var noteTypeID:Int; public var noteTypeID:Int;
/** /**
* ID of the player. * ID of the player.
*/ */
public var strumLineID:Int; public var strumLineID:Int;
/** /**
* Whenever the note will need to be hit by the player * Whenever the note will need to be hit by the player
*/ */
public var mustHit:Bool; public var mustHit:Bool;
/** /**
* Note sprite, if you only want to replace the sprite. * Note sprite, if you only want to replace the sprite.
*/ */
public var noteSprite:String; public var noteSprite:String;
/** /**
* Note scale, if you only want to replace the scale. * Note scale, if you only want to replace the scale.
*/ */
public var noteScale:Float; public var noteScale:Float;
/** /**
* Sing animation suffix. "-alt" for alt anim or "" for normal notes. * Sing animation suffix. "-alt" for alt anim or "" for normal notes.
*/ */
public var animSuffix:String; public var animSuffix:String;
} }
+156 -156
View File
@@ -4,170 +4,170 @@ import funkin.game.Note;
import funkin.game.Character; import funkin.game.Character;
class NoteHitEvent extends CancellableEvent { class NoteHitEvent extends CancellableEvent {
@:dox(hide) public var animCancelled:Bool = false; @:dox(hide) public var animCancelled:Bool = false;
@:dox(hide) public var strumGlowCancelled:Bool = false; @:dox(hide) public var strumGlowCancelled:Bool = false;
@:dox(hide) public var deleteNote:Bool = true; @:dox(hide) public var deleteNote:Bool = true;
@:dox(hide) public var unmuteVocals:Bool = true; @:dox(hide) public var unmuteVocals:Bool = true;
@:dox(hide) public var enableCamZooming:Bool = true; @:dox(hide) public var enableCamZooming:Bool = true;
@:dox(hide) public var autoHitLastSustain:Bool = true; @:dox(hide) public var autoHitLastSustain:Bool = true;
/** /**
* Whenever a miss should be added. * Whenever a miss should be added.
*/ */
public var misses:Bool = true; public var misses:Bool = true;
/** /**
* Whenever a miss should be added. * Whenever a miss should be added.
*/ */
public var countAsCombo:Bool = true; public var countAsCombo:Bool = true;
/** /**
* Whenever ratings should be shown or not. * Whenever ratings should be shown or not.
*/ */
public var showRating:Null<Bool> = null; public var showRating:Null<Bool> = null;
/** /**
* Note that has been pressed * Note that has been pressed
*/ */
public var note:Note; public var note:Note;
/** /**
* Character that pressed the note. * Character that pressed the note.
*/ */
public var character(get, set):Character; public var character(get, set):Character;
/** /**
* Characters that pressed the note. * Characters that pressed the note.
*/ */
public var characters:Array<Character>; public var characters:Array<Character>;
/** /**
* Whenever the Character is a player * Whenever the Character is a player
*/ */
public var player:Bool; public var player:Bool;
/** /**
* Note Type name (null if default note) * Note Type name (null if default note)
*/ */
public var noteType:String; public var noteType:String;
/** /**
* Suffix of the animation. "-alt" for alt notes, "" for normal ones. * Suffix of the animation. "-alt" for alt notes, "" for normal ones.
*/ */
public var animSuffix:String; public var animSuffix:String;
/** /**
* Prefix of the rating sprite path. Defaults to "game/score/" * Prefix of the rating sprite path. Defaults to "game/score/"
*/ */
public var ratingPrefix:String; public var ratingPrefix:String;
/** /**
* Suffix of the rating sprite path. * Suffix of the rating sprite path.
*/ */
public var ratingSuffix:String; public var ratingSuffix:String;
/** /**
* Direction of the press (0 = Left, 1 = Down, 2 = Up, 3 = Right) * Direction of the press (0 = Left, 1 = Down, 2 = Up, 3 = Right)
*/ */
public var direction:Int; public var direction:Int;
/** /**
* Score gained after note press. * Score gained after note press.
*/ */
public var score:Int; public var score:Int;
/** /**
* Accuracy gained from pressing this note. From 0 to 1. null means no accuracy is gained. * Accuracy gained from pressing this note. From 0 to 1. null means no accuracy is gained.
*/ */
public var accuracy:Null<Float>; public var accuracy:Null<Float>;
/** /**
* The amount of health that'll be gained from pressing that note. If called from `onPlayerMiss`, the value will be negative. * The amount of health that'll be gained from pressing that note. If called from `onPlayerMiss`, the value will be negative.
*/ */
public var healthGain:Float; public var healthGain:Float;
/** /**
* Rating name. Defaults to "sick", "good", "bad" and "shit". Customisable. * Rating name. Defaults to "sick", "good", "bad" and "shit". Customisable.
*/ */
public var rating:String = "sick"; public var rating:String = "sick";
/** /**
* Whenever a splash should be shown when the note is hit. * Whenever a splash should be shown when the note is hit.
*/ */
public var showSplash:Bool = false; public var showSplash:Bool = false;
/** /**
* Scale of combo numbers. * Scale of combo numbers.
*/ */
public var numScale:Float = 0.5; public var numScale:Float = 0.5;
/** /**
* Whenever antialiasing should be enabled on combo number. * Whenever antialiasing should be enabled on combo number.
*/ */
public var numAntialiasing:Bool = true; public var numAntialiasing:Bool = true;
/** /**
* Scale of ratings. * Scale of ratings.
*/ */
public var ratingScale:Float = 0.7; public var ratingScale:Float = 0.7;
/** /**
* Whenever antialiasing should be enabled on ratings. * Whenever antialiasing should be enabled on ratings.
*/ */
public var ratingAntialiasing:Bool = true; public var ratingAntialiasing:Bool = true;
/** /**
* Whenever the animation should be forced to play. * Whenever the animation should be forced to play.
*/ */
public var forceAnim:Bool = true; public var forceAnim:Bool = true;
/** /**
* Prevents the default sing animation from being played. * Prevents the default sing animation from being played.
*/ */
public function preventAnim() { public function preventAnim() {
animCancelled = true; animCancelled = true;
} }
@:dox(hide) @:dox(hide)
public function cancelAnim() {preventAnim();} public function cancelAnim() {preventAnim();}
/** /**
* Prevents the note from being deleted. * Prevents the note from being deleted.
*/ */
public function preventDeletion() { public function preventDeletion() {
deleteNote = false; deleteNote = false;
} }
@:dox(hide) @:dox(hide)
public function cancelDeletion() {preventDeletion();} public function cancelDeletion() {preventDeletion();}
/** /**
* Prevents the vocals volume from being set to 1 after pressing the note. * Prevents the vocals volume from being set to 1 after pressing the note.
*/ */
public function preventVocalsUnmute() { public function preventVocalsUnmute() {
unmuteVocals = false; unmuteVocals = false;
} }
@:dox(hide) @:dox(hide)
public function cancelVocalsUnmute() {preventVocalsUnmute();} public function cancelVocalsUnmute() {preventVocalsUnmute();}
/** /**
* Prevents the vocals volume from being muted in case its a parameter of `onPlayerMiss` * Prevents the vocals volume from being muted in case its a parameter of `onPlayerMiss`
*/ */
public function preventVocalsMute() { public function preventVocalsMute() {
unmuteVocals = true; unmuteVocals = true;
} }
@:dox(hide) @:dox(hide)
public function cancelVocalsMute() {preventVocalsMute();} public function cancelVocalsMute() {preventVocalsMute();}
/** /**
* Prevents the camera zoom every 4 beats from enabling. * Prevents the camera zoom every 4 beats from enabling.
*/ */
public function preventCamZooming() { public function preventCamZooming() {
enableCamZooming = false; enableCamZooming = false;
} }
@:dox(hide) @:dox(hide)
public function cancelCamZooming() {preventCamZooming();} public function cancelCamZooming() {preventCamZooming();}
/** /**
* Prevents the sustain tail (the last one) from being automatically hit when the sustain before it is hit. * Prevents the sustain tail (the last one) from being automatically hit when the sustain before it is hit.
*/ */
public function preventLastSustainHit() { public function preventLastSustainHit() {
autoHitLastSustain = false; autoHitLastSustain = false;
} }
@:dox(hide) @:dox(hide)
public function cancelLastSustainHit() {preventLastSustainHit();} public function cancelLastSustainHit() {preventLastSustainHit();}
/** /**
* Prevents the strum from glowing after this note has been pressed. * Prevents the strum from glowing after this note has been pressed.
*/ */
public function preventStrumGlow() { public function preventStrumGlow() {
strumGlowCancelled = true; strumGlowCancelled = true;
} }
@:dox(hide) @:dox(hide)
public function cancelStrumGlow() {preventStrumGlow();} public function cancelStrumGlow() {preventStrumGlow();}
private inline function get_character() private inline function get_character()
return characters[0]; return characters[0];
private function set_character(char:Character) { private function set_character(char:Character) {
characters = [char]; characters = [char];
return char; return char;
} }
} }
@@ -4,45 +4,45 @@ import funkin.game.Note;
import funkin.game.Strum; import funkin.game.Strum;
class NoteUpdateEvent extends CancellableEvent { class NoteUpdateEvent extends CancellableEvent {
@:dox(hide) public var __updateHitWindow = true; @:dox(hide) public var __updateHitWindow = true;
@:dox(hide) public var __autoCPUHit = true; @:dox(hide) public var __autoCPUHit = true;
@:dox(hide) public var __reposNote = true; @:dox(hide) public var __reposNote = true;
/** /**
* Note that is being updated * Note that is being updated
*/ */
public var note:Note; public var note:Note;
/** /**
* Time elapsed since last frame * Time elapsed since last frame
*/ */
public var elapsed:Null<Float>; public var elapsed:Null<Float>;
/** /**
* Note's strum (can be changed) * Note's strum (can be changed)
*/ */
public var strum:Strum; public var strum:Strum;
/** /**
* Cancels the hit window update. * Cancels the hit window update.
*/ */
public function cancelWindowUpdate() { public function cancelWindowUpdate() {
__updateHitWindow = false; __updateHitWindow = false;
} }
@:dox(hide) public function preventWindowUpdate() { cancelWindowUpdate(); } @:dox(hide) public function preventWindowUpdate() { cancelWindowUpdate(); }
/** /**
* Cancels the automatic CPU hit. * Cancels the automatic CPU hit.
*/ */
public function cancelAutoCPUHit() { public function cancelAutoCPUHit() {
__autoCPUHit = false; __autoCPUHit = false;
} }
@:dox(hide) public function preventAutoCPUHit() { cancelAutoCPUHit(); } @:dox(hide) public function preventAutoCPUHit() { cancelAutoCPUHit(); }
/** /**
* Cancels the note position update (note will freeze). * Cancels the note position update (note will freeze).
*/ */
public function cancelPositionUpdate() { public function cancelPositionUpdate() {
__reposNote = false; __reposNote = false;
} }
@:dox(hide) public function preventPositionUpdate() { cancelPositionUpdate(); } @:dox(hide) public function preventPositionUpdate() { cancelPositionUpdate(); }
} }
@@ -4,13 +4,13 @@ package funkin.scripting.events;
* CANCEL this event to prevent default behaviour! * CANCEL this event to prevent default behaviour!
*/ */
class PauseCreationEvent extends CancellableEvent { class PauseCreationEvent extends CancellableEvent {
/** /**
* Music that is going to be played * Music that is going to be played
*/ */
public var music:String; public var music:String;
/** /**
* All option names * All option names
*/ */
public var options:Array<String>; public var options:Array<String>;
} }
+46 -46
View File
@@ -1,64 +1,64 @@
package funkin.scripting.events; package funkin.scripting.events;
class PlayAnimEvent extends CancellableEvent { class PlayAnimEvent extends CancellableEvent {
/** /**
Name of the animation that's going to be played. Name of the animation that's going to be played.
**/ **/
public var animName:String; public var animName:String;
/** /**
Whenever the animation will be forced or not. Whenever the animation will be forced or not.
**/ **/
public var force:Bool; public var force:Bool;
/** /**
Whenever the animation will play in reverse or not Whenever the animation will play in reverse or not
**/ **/
public var reverse:Bool; public var reverse:Bool;
/** /**
The frame at which the animation will start playing The frame at which the animation will start playing
**/ **/
public var startingFrame:Int = 0; public var startingFrame:Int = 0;
/** /**
Context of the animation Context of the animation
**/ **/
public var context:PlayAnimContext; public var context:PlayAnimContext;
} }
/** /**
Contains all contexts possible for `PlayAnimEvent`. Contains all contexts possible for `PlayAnimEvent`.
**/ **/
@:enum @:enum
abstract PlayAnimContext(String) { abstract PlayAnimContext(String) {
/** /**
No context was given for the animation. No context was given for the animation.
The character won't dance until the animation is finished The character won't dance until the animation is finished
**/ **/
var NONE = null; var NONE = null;
/** /**
Whenever a note is hit and a sing animation will be played. Whenever a note is hit and a sing animation will be played.
The character will only dance after their holdTime is reached. The character will only dance after their holdTime is reached.
**/ **/
var SING = "SING"; var SING = "SING";
/** /**
Whenever a dance animation is played. Whenever a dance animation is played.
The character's dancing wont be blocked. The character's dancing wont be blocked.
**/ **/
var DANCE = "DANCE"; var DANCE = "DANCE";
/** /**
Whenever a note is missed and a miss animation will be played. Whenever a note is missed and a miss animation will be played.
Only for scripting, since it has the same effects as SING. Only for scripting, since it has the same effects as SING.
**/ **/
var MISS = "MISS"; var MISS = "MISS";
/** /**
Locks the character's animation. Locks the character's animation.
Prevents the character from dancing, even if the animation ended. Prevents the character from dancing, even if the animation ended.
**/ **/
var LOCK = "LOCK"; var LOCK = "LOCK";
} }
+8 -8
View File
@@ -1,12 +1,12 @@
package funkin.scripting.events; package funkin.scripting.events;
class PointEvent extends CancellableEvent { class PointEvent extends CancellableEvent {
/** /**
X position X position
**/ **/
public var x:Float; public var x:Float;
/** /**
Y position Y position
**/ **/
public var y:Float; public var y:Float;
} }
@@ -1,13 +1,13 @@
package funkin.scripting.events; package funkin.scripting.events;
class RatingUpdateEvent extends CancellableEvent { class RatingUpdateEvent extends CancellableEvent {
/** /**
New combo New combo
**/ **/
public var rating:ComboRating; public var rating:ComboRating;
/** /**
Old combo (may be null) Old combo (may be null)
**/ **/
public var oldRating:ComboRating; public var oldRating:ComboRating;
} }
+16 -16
View File
@@ -1,22 +1,22 @@
package funkin.scripting.events; package funkin.scripting.events;
class ResizeEvent extends CancellableEvent { class ResizeEvent extends CancellableEvent {
/** /**
* New width * New width
*/ */
public var width:Int; public var width:Int;
/** /**
* New height * New height
*/ */
public var height:Int; public var height:Int;
/** /**
* Old width (may be null) * Old width (may be null)
*/ */
public var oldWidth:Null<Int>; public var oldWidth:Null<Int>;
/** /**
* Old height (may be null) * Old height (may be null)
*/ */
public var oldHeight:Null<Int>; public var oldHeight:Null<Int>;
} }
@@ -3,8 +3,8 @@ package funkin.scripting.events;
import funkin.game.Note; import funkin.game.Note;
class SimpleNoteEvent extends CancellableEvent { class SimpleNoteEvent extends CancellableEvent {
/** /**
Note that is affected. Note that is affected.
**/ **/
public var note:Note; public var note:Note;
} }

Some files were not shown because too many files have changed in this diff Show More