Merge remote-tracking branch 'public/main'
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
ko_fi: codename_engine
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
build:
|
||||
name: Linux Build
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Pulling the source
|
||||
uses: actions/checkout@v2
|
||||
@@ -35,13 +35,13 @@ jobs:
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime build linux
|
||||
- name: Tar files
|
||||
run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
|
||||
# - name: Tar files
|
||||
# run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Codename Engine
|
||||
path: CodenameEngine.tar.gz
|
||||
path: export/release/linux/bin/
|
||||
# - name: Uploading artifact (executable)
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
|
||||
@@ -84,7 +84,6 @@ If you don't have a github account please go onto https://fnf-cne-devs.github.io
|
||||
<details>
|
||||
<summary><h2>Credits</h2></summary>
|
||||
|
||||
- Credits to [Ne_Eo](https://twitter.com/Ne_Eo_Twitch) and the [3D-HaxeFlixel](https://github.com/lunarcleint/3D-HaxeFlixel) repository for Away3D Flixel support
|
||||
- Credits to the [FlxAnimate](https://github.com/Dot-Stuff/flxanimate) team for the Animate Atlas support
|
||||
- Credits to Smokey555 for the backup Animate Atlas to spritesheet code
|
||||
- Credits to MAJigsaw77 for [hxvlc](https://github.com/MAJigsaw77/hxvlc) (video cutscene/mp4 support) and [hxdiscord_rpc](https://github.com/MAJigsaw77/hxdiscord_rpc) (discord rpc integration)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"clientID": "1027994136193810442",
|
||||
"clientID": "1383853614589673472",
|
||||
"logoKey": "icon"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
//
|
||||
function update(elapsed:Float)
|
||||
if (FlxG.keys.justPressed.F5) FlxG.resetState();
|
||||
@@ -18,9 +18,7 @@ public var daPixelZoom = PlayState.daPixelZoom;
|
||||
* UI
|
||||
*/
|
||||
function onNoteCreation(event) {
|
||||
if (event.note.strumLine == playerStrums && !pixelNotesForBF) return;
|
||||
if (event.note.strumLine == cpuStrums && !pixelNotesForDad) return;
|
||||
|
||||
if ((event.note.strumLine == playerStrums && !pixelNotesForBF) || (event.note.strumLine == cpuStrums && !pixelNotesForDad)) return;
|
||||
event.cancel();
|
||||
|
||||
var note = event.note;
|
||||
@@ -34,18 +32,14 @@ function onNoteCreation(event) {
|
||||
}
|
||||
note.scale.set(daPixelZoom, daPixelZoom);
|
||||
note.updateHitbox();
|
||||
note.antialiasing = false;
|
||||
}
|
||||
|
||||
function onPostNoteCreation(event) {
|
||||
var splashes = event.note;
|
||||
if (pixelSplashes)
|
||||
splashes.splash = "pixel-default";
|
||||
}
|
||||
function onPostNoteCreation(event) if (pixelSplashes)
|
||||
event.note.splash = "pixel-default";
|
||||
|
||||
function onStrumCreation(event) {
|
||||
if (event.player == 1 && !pixelNotesForBF) return;
|
||||
if (event.player == 0 && !pixelNotesForDad) return;
|
||||
|
||||
if ((event.player == 1 && !pixelNotesForBF) || (event.player == 0 && !pixelNotesForDad)) return;
|
||||
event.cancel();
|
||||
|
||||
var strum = event.strum;
|
||||
@@ -56,6 +50,7 @@ function onStrumCreation(event) {
|
||||
|
||||
strum.scale.set(daPixelZoom, daPixelZoom);
|
||||
strum.updateHitbox();
|
||||
strum.antialiasing = false;
|
||||
}
|
||||
|
||||
function onCountdown(event) {
|
||||
@@ -86,9 +81,9 @@ function onPlayerHit(event:NoteHitEvent) {
|
||||
* CAMERA HACKS!!
|
||||
*/
|
||||
function postCreate() {
|
||||
if (enablePauseMenu) {
|
||||
if (enablePauseMenu)
|
||||
PauseSubState.script = 'data/scripts/week6-pause';
|
||||
}
|
||||
|
||||
if (enableCameraHacks) {
|
||||
camGame.pixelPerfectRender = true;
|
||||
camGame.antialiasing = false;
|
||||
@@ -104,8 +99,8 @@ function postCreate() {
|
||||
}
|
||||
}
|
||||
|
||||
function onStartCountdown() {
|
||||
/*var newNoteCamera = new HudCamera();
|
||||
/*function onStartCountdown() {
|
||||
var newNoteCamera = new HudCamera();
|
||||
newNoteCamera.bgColor = 0; // transparent
|
||||
FlxG.cameras.add(newNoteCamera, false);
|
||||
|
||||
@@ -119,8 +114,8 @@ function onStartCountdown() {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
makeCameraPixely(newNoteCamera);*/
|
||||
}
|
||||
makeCameraPixely(newNoteCamera);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Use this to make any camera pixelly (you wont be able to zoom with it anymore!)
|
||||
@@ -145,33 +140,29 @@ function destroy() {
|
||||
FlxG.game.stage.quality = oldStageQuality;
|
||||
}
|
||||
|
||||
function pixelCam(cam) {
|
||||
function pixelCam(cam)
|
||||
makeCameraPixely(cam);
|
||||
}
|
||||
|
||||
var pixellyCameras = [];
|
||||
var pixellyShaders = [];
|
||||
|
||||
function postUpdate(elapsed) {
|
||||
for(e in pixellyCameras) {
|
||||
if (Std.isOfType(e, HudCamera))
|
||||
e.downscroll = camHUD.downscroll;
|
||||
}
|
||||
if (enableCameraHacks) {
|
||||
for(p in strumLines)
|
||||
p.notes.forEach(function(n) {
|
||||
if(n.isSustainNote) return; // hacky fix for hold
|
||||
n.y -= n.y % daPixelZoom;
|
||||
n.x -= n.x % daPixelZoom;
|
||||
});
|
||||
function postUpdate() {
|
||||
for (e in pixellyCameras) if (Std.isOfType(e, HudCamera))
|
||||
e.downscroll = camHUD.downscroll;
|
||||
|
||||
if (enableCameraHacks) for (p in strumLines) {
|
||||
p.notes.forEach(function(n) {
|
||||
if(n.isSustainNote) return; // hacky fix for hold
|
||||
n.y -= n.y % daPixelZoom;
|
||||
n.x -= n.x % daPixelZoom;
|
||||
});
|
||||
}
|
||||
|
||||
var zoom = 1 / daPixelZoom / Math.min(FlxG.scaleMode.scale.x, FlxG.scaleMode.scale.y);
|
||||
for(e in pixellyCameras) {
|
||||
for (e in pixellyCameras) {
|
||||
if (!e.exists) continue;
|
||||
e.zoom = zoom;
|
||||
}
|
||||
for(e in pixellyShaders) {
|
||||
for (e in pixellyShaders)
|
||||
e.pixelZoom = zoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import flixel.text.FlxText;
|
||||
import flixel.text.FlxTextBorderStyle;
|
||||
import flixel.util.FlxAxes;
|
||||
|
||||
var pixelScript:Script;
|
||||
var pixelScript:Script = game.scripts.getByName("pixel.hx");
|
||||
var pauseCam = new FlxCamera();
|
||||
|
||||
var bg:FlxSprite;
|
||||
@@ -19,47 +19,40 @@ function create(event) {
|
||||
|
||||
event.music = isThorns ? "pixel/LunchboxScary" : "pixel/breakfast";
|
||||
|
||||
cameras = [];
|
||||
|
||||
pixelScript = game.scripts.getByName("pixel.hx");
|
||||
pixelScript.call("pixelCam", [pauseCam]);
|
||||
// allowing this pause script even if the pixel script is not loaded - Nex
|
||||
pixelScript?.call("pixelCam", [pauseCam]);
|
||||
|
||||
FlxG.cameras.add(pauseCam, false);
|
||||
cameras = [pauseCam];
|
||||
|
||||
pauseCam.bgColor = isThorns ? 0x88000000 : 0x88FF99CC;
|
||||
pauseCam.alpha = 0;
|
||||
|
||||
bg = new FlxSprite(44 * 6, 14 * 6);
|
||||
bg.loadGraphic(Paths.image('stages/school/pause/bg'));
|
||||
if (isThorns)
|
||||
bg.color = 0xFF000000;
|
||||
bg = new FlxSprite(44 * 6, 14 * 6, Paths.image('stages/school/pause/bg'));
|
||||
bg.antialiasing = false;
|
||||
if (isThorns) bg.color = 0xFF000000;
|
||||
bg.scale.set(6, 6);
|
||||
bg.updateHitbox();
|
||||
bg.scale.y = 4;
|
||||
bg.cameras = [pauseCam];
|
||||
add(bg);
|
||||
|
||||
songText = new FlxText(0, 22 * 6, 0, "Pause", 8, false);
|
||||
confText(songText);
|
||||
add(songText);
|
||||
|
||||
var i = 2;
|
||||
for(e in menuItems) {
|
||||
text = new FlxText(0, (22 * 6) + (i * 9 * 6), 0, e, 8, false);
|
||||
for (i=>e in menuItems) {
|
||||
text = new FlxText(0, (22 * 6) + ((i+2) * 9 * 6), 0, e, 8, false);
|
||||
confText(text);
|
||||
add(text);
|
||||
texts.push(text);
|
||||
i++;
|
||||
}
|
||||
|
||||
hand = new FlxSprite().loadGraphic(Paths.image('stages/school/ui/hand_textbox'));
|
||||
hand.antialiasing = false;
|
||||
hand.scale.set(6, 6);
|
||||
hand.updateHitbox();
|
||||
add(hand);
|
||||
|
||||
FlxTween.tween(bg, {"scale.y": 6}, 0.75, {ease: FlxEase.elasticOut});
|
||||
FlxTween.tween(bg.scale, {y: 6}, 0.75, {ease: FlxEase.elasticOut});
|
||||
|
||||
cameras = [pauseCam];
|
||||
|
||||
FlxG.sound.play(Paths.sound(isThorns ? 'pixel/ANGRY' : 'pixel/clickText'));
|
||||
}
|
||||
@@ -70,55 +63,50 @@ function confText(text) {
|
||||
text.screenCenter(FlxAxes.X);
|
||||
text.borderStyle = FlxTextBorderStyle.OUTLINE;
|
||||
if (!isThorns) text.borderColor = 0xFF953E3E;
|
||||
|
||||
text.antialiasing = false;
|
||||
texts.push(text);
|
||||
add(text);
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
if(FlxG.cameras.list.contains(pauseCam))
|
||||
FlxG.cameras.remove(pauseCam);
|
||||
}
|
||||
function destroy() if (FlxG.cameras.list.contains(pauseCam))
|
||||
FlxG.cameras.remove(pauseCam);
|
||||
|
||||
var canDoShit = true;
|
||||
var time:Float = 0;
|
||||
function update(elapsed) {
|
||||
pixelScript.call("postUpdate", [elapsed]);
|
||||
pixelScript?.call("postUpdate", [elapsed]);
|
||||
|
||||
pauseCam.alpha = lerp(pauseCam.alpha, 1, 0.25);
|
||||
time += elapsed;
|
||||
|
||||
var curText = texts[curSelected];
|
||||
var curText = texts[curSelected + 1];
|
||||
hand.setPosition(curText.x - hand.width - 18 + (Math.sin(time * Math.PI * 2) * 12), curText.y + (text.height - hand.height) - 6);
|
||||
hand.x -= hand.x % 6;
|
||||
hand.y -= hand.y % 6;
|
||||
|
||||
if (!canDoShit) return;
|
||||
var oldSec = curSelected;
|
||||
|
||||
changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0) - FlxG.mouse.wheel);
|
||||
|
||||
if (oldSec != curSelected)
|
||||
FlxG.sound.play(Paths.sound(isThorns ? 'pixel/type' : 'pixel/pixelText'));
|
||||
if (controls.ACCEPT) enterOption();
|
||||
}
|
||||
|
||||
if (controls.ACCEPT) {
|
||||
FlxG.sound.play(Paths.sound(isThorns ? 'pixel/ANGRY' : 'pixel/clickText'));
|
||||
var option = menuItems[curSelected];
|
||||
if (option == "Resume" || option == "Exit to menu") {
|
||||
var scrollSFX = FlxG.sound.load(Paths.sound(isThorns ? 'pixel/type' : 'pixel/pixelText'));
|
||||
function changeSelection(change) if (canDoShit) { // this overrides the function inside of the normal pause btw, so no event gets called - Nex
|
||||
curSelected = FlxMath.wrap(curSelected + change, 0, menuItems.length - 1);
|
||||
if (change != 0) scrollSFX.play();
|
||||
}
|
||||
|
||||
var enterSFX = FlxG.sound.load(Paths.sound(isThorns ? 'pixel/ANGRY' : 'pixel/clickText'));
|
||||
function enterOption() if (canDoShit) {
|
||||
var option = menuItems[curSelected];
|
||||
enterSFX.play();
|
||||
|
||||
switch(option) {
|
||||
case "Resume", "Exit to menu":
|
||||
canDoShit = false;
|
||||
for(t in texts) t.visible = false;
|
||||
hand.visible = songText.visible = false;
|
||||
FlxTween.tween(bg, {"scale.y": 0}, 0.125, {ease: FlxEase.cubeOut, onComplete: function() {
|
||||
selectOption();
|
||||
}});
|
||||
} else {
|
||||
selectOption();
|
||||
}
|
||||
FlxTween.tween(bg.scale, {y: 0}, 0.125, {ease: FlxEase.cubeOut, onComplete: selectOption});
|
||||
default: selectOption();
|
||||
}
|
||||
}
|
||||
|
||||
function changeSelection(change) { // this overrides the function inside of the normal pause btw, so no event gets called - Nex
|
||||
curSelected += change;
|
||||
|
||||
if (curSelected < 0)
|
||||
curSelected = menuItems.length - 1;
|
||||
if (curSelected >= menuItems.length)
|
||||
curSelected = 0;
|
||||
}
|
||||
@@ -3,13 +3,7 @@ var sound:Sound;
|
||||
function create()
|
||||
sound = Paths.sound('jeffGameover/jeffGameover-' + FlxG.random.int(1, 25, !Options.naughtyness ? [1, 3, 8, 13, 17, 21] : null));
|
||||
|
||||
function beatHit(cur:Int) {
|
||||
if(cur != 0) return;
|
||||
|
||||
function beatHit(cur:Int) if (cur == 0) {
|
||||
FlxG.sound.play(sound, 1, false, null, true, () -> if (!isEnding) FlxG.sound.music.fadeIn(4, 0.2, 1));
|
||||
FlxG.sound.music.volume = 0.2;
|
||||
FlxG.sound.play(sound, 1, false, null, true, function()
|
||||
{
|
||||
if (!isEnding)
|
||||
FlxG.sound.music.fadeIn(4, 0.2, 1);
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
var tankAngle:Float = FlxG.random.int(-90, 45);
|
||||
var tankSpeed:Float = FlxG.random.float(5, 7);
|
||||
|
||||
function postCreate() if(PlayState.isStoryMode)
|
||||
function postCreate() if (PlayState.isStoryMode)
|
||||
GameOverSubstate.script = 'data/scripts/week7-balledLines';
|
||||
|
||||
function update(elapsed:Float) {
|
||||
@@ -12,7 +12,7 @@ function update(elapsed:Float) {
|
||||
}
|
||||
|
||||
function onPostCountdown(event) {
|
||||
if(!playCutscenes || event.sprite == null) return;
|
||||
if (!playCutscenes || event.sprite == null) return;
|
||||
var lastIndex:Int = members.indexOf(event.sprite);
|
||||
remove(event.sprite);
|
||||
insert(lastIndex + 4, event.sprite);
|
||||
|
||||
@@ -15,10 +15,8 @@ class Compiler {
|
||||
}
|
||||
|
||||
private static function __build(args:Array<String>, arg:Array<String>) {
|
||||
arg.insert(0, "lime");
|
||||
arg.insert(0, "run");
|
||||
for(a in args)
|
||||
arg.push(a);
|
||||
for (a in args) arg.push(a);
|
||||
arg = ['run', 'lime'].concat(arg);
|
||||
Sys.command("haxelib", arg);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
title="Friday Night Funkin' - Codename Engine" main="funkin.backend.system.Main"
|
||||
file="CodenameEngine" packageName="com.yoshman29.codenameengine"
|
||||
package="com.yoshman29.codenameengine"
|
||||
version="0.1.0" company="Yoshman29" />
|
||||
version="0.1.0-legacy" company="Yoshman29" />
|
||||
|
||||
<!--
|
||||
CHANGE THE SAVE PATH & NAME FOR YOUR MOD HERE!
|
||||
|
||||
@@ -105,6 +105,8 @@ class MusicBeatState extends FlxState implements IBeatReceiver
|
||||
public static var skipTransOut:Bool = false;
|
||||
public static var skipTransIn:Bool = false;
|
||||
|
||||
public static var ALLOW_DEBUG_RELOAD:Bool = true;
|
||||
|
||||
inline function get_controls():Controls
|
||||
return PlayerSettings.solo.controls;
|
||||
inline function get_controlsP1():Controls
|
||||
@@ -151,16 +153,20 @@ class MusicBeatState extends FlxState implements IBeatReceiver
|
||||
call("postUpdate", [elapsed]);
|
||||
}
|
||||
|
||||
if (_requestSubStateReset)
|
||||
{
|
||||
if (_requestSubStateReset) {
|
||||
_requestSubStateReset = false;
|
||||
resetSubState();
|
||||
}
|
||||
if (subState != null)
|
||||
{
|
||||
subState.tryUpdate(elapsed);
|
||||
|
||||
if (/*subState == null && */(ALLOW_DEBUG_RELOAD && controls.DEBUG_RELOAD)) {
|
||||
Logs.trace("Reloading Current State...", INFO, YELLOW);
|
||||
FlxG.resetState();
|
||||
}
|
||||
|
||||
if (subState != null)
|
||||
subState.tryUpdate(elapsed);
|
||||
}
|
||||
|
||||
override function create()
|
||||
{
|
||||
loadScript();
|
||||
@@ -221,10 +227,6 @@ class MusicBeatState extends FlxState implements IBeatReceiver
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
// TODO: DEBUG MODE!!
|
||||
if (FlxG.keys.justPressed.F5) {
|
||||
loadScript();
|
||||
}
|
||||
call("update", [elapsed]);
|
||||
|
||||
super.update(elapsed);
|
||||
|
||||
@@ -134,15 +134,19 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
|
||||
call("postUpdate", [elapsed]);
|
||||
}
|
||||
|
||||
if (_requestSubStateReset)
|
||||
{
|
||||
// if (subState == null && (MusicBeatState.ALLOW_DEBUG_RELOAD && controls.DEBUG_RELOAD)) {
|
||||
// Logs.trace("Reloading Current SubState...", INFO, YELLOW);
|
||||
// var test = Type.createInstance(Type.getClass(this), [this.scriptsAllowed, this.scriptName]);
|
||||
// parent.openSubState(test);
|
||||
// }
|
||||
|
||||
if (_requestSubStateReset) {
|
||||
_requestSubStateReset = false;
|
||||
resetSubState();
|
||||
}
|
||||
|
||||
if (subState != null)
|
||||
{
|
||||
subState.tryUpdate(elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
override function close() {
|
||||
@@ -179,10 +183,6 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
// TODO: DEBUG MODE!!
|
||||
if (FlxG.keys.justPressed.F5) {
|
||||
loadScript();
|
||||
}
|
||||
call("update", [elapsed]);
|
||||
super.update(elapsed);
|
||||
}
|
||||
|
||||
@@ -25,10 +25,7 @@ class ModsFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
this.folderPath = folderPath;
|
||||
this.libName = libName;
|
||||
this.prefix = 'assets/$libName/';
|
||||
if(modName == null)
|
||||
this.modName = libName;
|
||||
else
|
||||
this.modName = modName;
|
||||
this.modName = modName == null ? libName : modName;
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@@ -268,13 +268,13 @@ class Paths
|
||||
}
|
||||
return content;
|
||||
}
|
||||
static public function getFolderContent(key:String, addPath:Bool = false, source:AssetsLibraryList.AssetSource = BOTH):Array<String> {
|
||||
static public function getFolderContent(key:String, addPath:Bool = false, source:AssetsLibraryList.AssetSource = BOTH, noExtension:Bool = false):Array<String> {
|
||||
// designed to work both on windows and web
|
||||
if (!key.endsWith("/")) key += "/";
|
||||
var content = assetsTree.getFiles('assets/$key', source);
|
||||
if (addPath) {
|
||||
for(k=>e in content)
|
||||
content[k] = '$key$e';
|
||||
for (k => e in content) {
|
||||
if (noExtension) e = Path.withoutExtension(e);
|
||||
content[k] = addPath ? '$key$e' : e;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -82,30 +82,29 @@ class Chart {
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function loadChartMeta(songName:String, ?difficulty:String, fromMods:Bool = true) {
|
||||
public static function loadChartMeta(songName:String, ?difficulty:String, fromMods:Bool = true):ChartMetaData {
|
||||
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
|
||||
|
||||
|
||||
var metaPath = Paths.file('songs/${songName}/meta.json');
|
||||
var metaDiffPath = Paths.file('songs/${songName}/meta-${difficulty}.json');
|
||||
|
||||
var data:ChartMetaData = null;
|
||||
var fromMods:Bool = fromMods;
|
||||
for(path in [metaDiffPath, metaPath]) {
|
||||
if (Assets.exists(path)) {
|
||||
fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS);
|
||||
try {
|
||||
data = Json.parse(Assets.getText(path));
|
||||
} catch(e) {
|
||||
Logs.trace('Failed to load song metadata for ${songName} ($path): ${Std.string(e)}', ERROR);
|
||||
}
|
||||
if (data != null) break;
|
||||
}
|
||||
for (path in [metaDiffPath, metaPath]) if (Assets.exists(path)) {
|
||||
fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS);
|
||||
try {
|
||||
var tempData = Json.parse(Assets.getText(path));
|
||||
tempData.color = CoolUtil.getColorFromDynamic(tempData.color).getDefault(Flags.DEFAULT_COLOR);
|
||||
data = tempData;
|
||||
} catch(e) Logs.trace('Failed to load song metadata for ${songName} ($path): ${Std.string(e)}', ERROR);
|
||||
if (data != null) break;
|
||||
}
|
||||
|
||||
if (data == null)
|
||||
data = {
|
||||
name: songName
|
||||
};
|
||||
if (data == null) data = {
|
||||
name: songName,
|
||||
bpm: 100
|
||||
};
|
||||
|
||||
data.setFieldDefault("name", songName);
|
||||
data.setFieldDefault("bpm", Flags.DEFAULT_BPM);
|
||||
data.setFieldDefault("beatsPerMeasure", Flags.DEFAULT_BEATS_PER_MEASURE);
|
||||
@@ -116,7 +115,6 @@ class Chart {
|
||||
data.setFieldDefault("coopAllowed", Flags.DEFAULT_COOP_ALLOWED);
|
||||
data.setFieldDefault("opponentModeAllowed", Flags.DEFAULT_OPPONENT_MODE_ALLOWED);
|
||||
data.setFieldDefault("displayName", data.name);
|
||||
data.setFieldDefault("parsedColor", data.color.getColorFromDynamic().getDefault(Flags.DEFAULT_COLOR));
|
||||
|
||||
if (data.difficulties.length <= 0) {
|
||||
data.difficulties = [for(f in Paths.getFolderContent('songs/${songName}/charts/', false, fromMods ? MODS : SOURCE)) if (Path.extension(f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
|
||||
@@ -159,11 +157,9 @@ class Chart {
|
||||
valid = false;
|
||||
}
|
||||
var data:Dynamic = null;
|
||||
try {
|
||||
if (valid)
|
||||
data = Json.parse(Assets.getText(chartPath));
|
||||
} catch(e) {
|
||||
Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED);
|
||||
if (valid) {
|
||||
try data = Json.parse(Assets.getText(chartPath))
|
||||
catch(e) Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,8 +220,7 @@ class Chart {
|
||||
return 0;
|
||||
default:
|
||||
var index = chart.noteTypes.indexOf(noteTypeName);
|
||||
if (index > -1)
|
||||
return index+1;
|
||||
if (index > -1) return index + 1;
|
||||
chart.noteTypes.push(noteTypeName);
|
||||
return chart.noteTypes.length;
|
||||
}
|
||||
@@ -260,33 +255,33 @@ class Chart {
|
||||
|
||||
CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null));
|
||||
|
||||
// idk how null reacts to it so better be sure
|
||||
if (saveSettings.overrideExistingMeta == true || !FileSystem.exists(metaPath))
|
||||
CoolUtil.safeSaveFile(metaPath, Json.stringify(meta, null, saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null));
|
||||
CoolUtil.safeSaveFile(metaPath, makeMetaSaveable(meta));
|
||||
#end
|
||||
return filteredChart;
|
||||
}
|
||||
|
||||
public static function filterChartForSaving(chart:ChartData, ?saveMetaInChart:Null<Bool>, ?saveEventsInChart:Null<Bool>):ChartData {
|
||||
var data = Reflect.copy(chart); // make a copy of the chart to leave the OG intact
|
||||
if (saveMetaInChart != true) {
|
||||
data.meta = null;
|
||||
} else {
|
||||
data.meta = Reflect.copy(chart.meta); // also make a copy of the metadata to leave the OG intact.
|
||||
if(data.meta != null && Reflect.hasField(data.meta, "parsedColor")) Reflect.deleteField(data.meta, "parsedColor");
|
||||
}
|
||||
data.meta = saveMetaInChart != true ? null : data.meta = Reflect.copy(chart.meta); // also make a copy of the metadata to leave the OG intact.
|
||||
|
||||
data.events = saveEventsInChart != true ? null : Reflect.copy(chart.events); // same here once again
|
||||
data.fromMods = null;
|
||||
|
||||
var sortedData:Dynamic = {};
|
||||
for(f in Reflect.fields(data)) {
|
||||
for (f in Reflect.fields(data)) {
|
||||
var v = Reflect.field(data, f);
|
||||
if (v != null)
|
||||
Reflect.setField(sortedData, f, v);
|
||||
}
|
||||
return sortedData;
|
||||
}
|
||||
|
||||
public static inline function makeMetaSaveable(meta:ChartMetaData, prettyPrint:Bool = true):String {
|
||||
var data:Dynamic = Reflect.copy(meta);
|
||||
if (data.color != null) data.color = new FlxColor(data.color).toWebString(); // dont even ask me - Nex
|
||||
return Json.stringify(data, null, prettyPrint ? Flags.JSON_PRETTY_PRINT : null);
|
||||
}
|
||||
}
|
||||
|
||||
typedef ChartSaveSettings = {
|
||||
|
||||
@@ -21,15 +21,12 @@ typedef ChartMetaData = {
|
||||
public var ?beatsPerMeasure:Float;
|
||||
public var ?stepsPerBeat:Int;
|
||||
public var ?icon:String;
|
||||
public var ?color:Dynamic;
|
||||
public var ?color:FlxColor;
|
||||
public var ?difficulties:Array<String>;
|
||||
public var ?coopAllowed:Bool;
|
||||
public var ?opponentModeAllowed:Bool;
|
||||
public var ?customValues:Dynamic;
|
||||
public var ?needsVoices:Bool;
|
||||
|
||||
// NOT TO BE EXPORTED
|
||||
public var ?parsedColor:FlxColor;
|
||||
}
|
||||
|
||||
typedef ChartStrumLine = {
|
||||
|
||||
@@ -12,6 +12,8 @@ class GlobalScript {
|
||||
public static var scripts:ScriptPack;
|
||||
|
||||
private static var initialized:Bool = false;
|
||||
private static var reloading:Bool = false;
|
||||
private static var _lastAllow_Reload:Bool = false;
|
||||
|
||||
public static function init() {
|
||||
if(initialized) return;
|
||||
@@ -46,16 +48,12 @@ class GlobalScript {
|
||||
});
|
||||
FlxG.signals.postUpdate.add(function() {
|
||||
call("postUpdate", [FlxG.elapsed]);
|
||||
if (FlxG.keys.justPressed.F5) {
|
||||
if (scripts.scripts.length > 0) {
|
||||
Logs.trace('Reloading global script...', WARNING, YELLOW);
|
||||
scripts.reload();
|
||||
Logs.trace('Global script successfully reloaded.', WARNING, GREEN);
|
||||
} else {
|
||||
Logs.trace('Loading global script...', WARNING, YELLOW);
|
||||
onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end);
|
||||
}
|
||||
|
||||
if (reloading) {
|
||||
reloading = false;
|
||||
MusicBeatState.ALLOW_DEBUG_RELOAD = _lastAllow_Reload;
|
||||
}
|
||||
|
||||
if (FlxG.keys.justPressed.F2)
|
||||
NativeAPI.allocConsole();
|
||||
});
|
||||
@@ -74,13 +72,29 @@ class GlobalScript {
|
||||
FlxG.signals.preStateSwitch.add(function() {
|
||||
call("preStateSwitch", []);
|
||||
});
|
||||
|
||||
FlxG.signals.preUpdate.add(function() {
|
||||
call("preUpdate", [FlxG.elapsed]);
|
||||
call("update", [FlxG.elapsed]);
|
||||
});
|
||||
|
||||
// Commented this out, because it might be the cause why global runs twice - Neo
|
||||
//onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end);
|
||||
if (FlxG.keys.pressed.SHIFT) {
|
||||
var resetKey = FlxG.keys.justPressed.F5; // we default the key to F5, but really this shouldn't matter, as every state will be at minimum a MusicBeatState.
|
||||
if ((FlxG.state is MusicBeatState)) resetKey = cast(FlxG.state, MusicBeatState).controls.DEBUG_RELOAD;
|
||||
|
||||
// If we want, we could just make reseting GlobalScript it's own keybind, but for now this works.
|
||||
if (resetKey) {
|
||||
reloading = true;
|
||||
Logs.trace("Reloading Global Scripts...", INFO, YELLOW);
|
||||
|
||||
// yeah its a bit messy, sorry. This just prevents actually reloading the actual state.
|
||||
_lastAllow_Reload = MusicBeatState.ALLOW_DEBUG_RELOAD;
|
||||
MusicBeatState.ALLOW_DEBUG_RELOAD = false;
|
||||
|
||||
// Would be better to just re-initalize GlobalScript so there aren't any lose ends.
|
||||
onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static function event<T:CancellableEvent>(name:String, event:T):T {
|
||||
@@ -93,6 +107,7 @@ class GlobalScript {
|
||||
if (scripts != null)
|
||||
scripts.call(name, args);
|
||||
}
|
||||
|
||||
public static function onModSwitch(newMod:String) {
|
||||
call("destroy");
|
||||
scripts = FlxDestroyUtil.destroy(scripts);
|
||||
|
||||
@@ -83,7 +83,7 @@ class ScriptPack extends Script {
|
||||
**/
|
||||
public override function call(func:String, ?parameters:Array<Dynamic>):Dynamic {
|
||||
for(e in scripts)
|
||||
if(e.active)
|
||||
if (e.active)
|
||||
e.call(func, parameters);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package funkin.backend.scripting.events.menu.storymenu;
|
||||
|
||||
import funkin.menus.StoryMenuState.WeekData;
|
||||
import funkin.backend.week.WeekData;
|
||||
|
||||
final class WeekSelectEvent extends CancellableEvent {
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,9 @@ enum Control
|
||||
PAUSE;
|
||||
//CHEAT;
|
||||
SWITCHMOD;
|
||||
|
||||
// Debugs
|
||||
DEBUG_RELOAD;
|
||||
}
|
||||
|
||||
enum KeyboardScheme
|
||||
@@ -150,6 +153,11 @@ class Controls extends FlxActionSet
|
||||
@:pressed("switchmod") public var SWITCHMOD_HOLD(get, set): Bool;
|
||||
@:justReleased("switchmod") public var SWITCHMOD_R(get, set): Bool;
|
||||
|
||||
@:gamepad([GUIDE]) // the center button (like the PS button on a playstation controller) on the gamepad
|
||||
@:justPressed("debug-reload") public var DEBUG_RELOAD(get, set): Bool;
|
||||
@:pressed("debug-reload") public var DEBUG_RELOAD_HOLD(get, set): Bool;
|
||||
@:justReleased("debug-reload") public var DEBUG_RELOAD_R(get, set): Bool;
|
||||
|
||||
var byName:Map<String, FlxActionDigital> = [];
|
||||
|
||||
public var gamepadsAdded:Array<Int> = [];
|
||||
|
||||
@@ -79,7 +79,7 @@ class Main extends Sprite
|
||||
public static var audioDisconnected:Bool = false;
|
||||
|
||||
public static var changeID:Int = 0;
|
||||
public static var pathBack = #if windows
|
||||
public static var pathBack = #if (windows || linux)
|
||||
"../../../../"
|
||||
#elseif mac
|
||||
"../../../../../../../"
|
||||
@@ -175,6 +175,8 @@ class Main extends Sprite
|
||||
}
|
||||
|
||||
public static function refreshAssets() @:privateAccess {
|
||||
FunkinCache.instance.clearSecondLayer();
|
||||
|
||||
var game = FlxG.game;
|
||||
var daSndTray = Type.createInstance(game._customSoundTray = funkin.menus.ui.FunkinSoundTray, []);
|
||||
var index:Int = game.numChildren - 1;
|
||||
|
||||
@@ -6,16 +6,21 @@ import sys.FileSystem;
|
||||
import flixel.FlxState;
|
||||
import funkin.backend.assets.ModsFolder;
|
||||
import funkin.backend.chart.EventsData;
|
||||
import funkin.menus.BetaWarningState;
|
||||
import funkin.menus.TitleState;
|
||||
import funkin.backend.system.framerate.Framerate;
|
||||
import funkin.menus.TitleState;
|
||||
import haxe.io.Path;
|
||||
|
||||
@dox(hide)
|
||||
typedef AddonInfo = {
|
||||
var name:String;
|
||||
var path:String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple state used for loading the game
|
||||
*/
|
||||
class MainState extends FlxState {
|
||||
public static var initiated:Bool = false;
|
||||
public static var betaWarningShown:Bool = false;
|
||||
public override function create() {
|
||||
super.create();
|
||||
if (!initiated) {
|
||||
@@ -35,25 +40,64 @@ class MainState extends FlxState {
|
||||
Paths.assetsTree.reset();
|
||||
|
||||
#if MOD_SUPPORT
|
||||
var _lowPriorityAddons:Array<String> = [];
|
||||
var _highPriorityAddons:Array<String> = [];
|
||||
var _noPriorityAddons:Array<String> = [];
|
||||
if (FileSystem.exists(ModsFolder.addonsPath) && FileSystem.isDirectory(ModsFolder.addonsPath)) {
|
||||
for(i=>addon in [for(dir in FileSystem.readDirectory(ModsFolder.addonsPath)) if (FileSystem.isDirectory('${ModsFolder.addonsPath}$dir')) dir]) {
|
||||
if (addon.startsWith("[LOW]")) _lowPriorityAddons.insert(0, addon);
|
||||
else if (addon.startsWith("[HIGH]")) _highPriorityAddons.insert(0, addon);
|
||||
else _noPriorityAddons.insert(0, addon);
|
||||
}
|
||||
for (addon in _lowPriorityAddons)
|
||||
Paths.assetsTree.addLibrary(ModsFolder.loadModLib('${ModsFolder.addonsPath}$addon', StringTools.ltrim(addon.substr("[LOW]".length))));
|
||||
}
|
||||
if (ModsFolder.currentModFolder != null)
|
||||
Paths.assetsTree.addLibrary(ModsFolder.loadModLib('${ModsFolder.modsPath}${ModsFolder.currentModFolder}', ModsFolder.currentModFolder));
|
||||
inline function isDirectory(path:String):Bool
|
||||
return FileSystem.exists(path) && FileSystem.isDirectory(path);
|
||||
|
||||
if (FileSystem.exists(ModsFolder.addonsPath) && FileSystem.isDirectory(ModsFolder.addonsPath)){
|
||||
for (addon in _noPriorityAddons) Paths.assetsTree.addLibrary(ModsFolder.loadModLib('${ModsFolder.addonsPath}$addon', addon));
|
||||
for (addon in _highPriorityAddons) Paths.assetsTree.addLibrary(ModsFolder.loadModLib('${ModsFolder.addonsPath}$addon', StringTools.ltrim(addon.substr("[HIGH]".length))));
|
||||
inline function ltrim(str:String, prefix:String):String
|
||||
return str.substr(prefix.length).ltrim();
|
||||
|
||||
inline function loadLib(path:String, name:String)
|
||||
Paths.assetsTree.addLibrary(ModsFolder.loadModLib(path, name));
|
||||
|
||||
var _lowPriorityAddons:Array<AddonInfo> = [];
|
||||
var _highPriorityAddons:Array<AddonInfo> = [];
|
||||
var _noPriorityAddons:Array<AddonInfo> = [];
|
||||
|
||||
var addonPaths = [
|
||||
ModsFolder.addonsPath,
|
||||
(
|
||||
ModsFolder.currentModFolder != null ?
|
||||
ModsFolder.modsPath + ModsFolder.currentModFolder + "/addons/" :
|
||||
null
|
||||
)
|
||||
];
|
||||
|
||||
for(path in addonPaths) {
|
||||
if (path == null) continue;
|
||||
if (!isDirectory(path)) continue;
|
||||
|
||||
for(addon in FileSystem.readDirectory(path)) {
|
||||
if(!FileSystem.isDirectory(path + addon)) {
|
||||
switch(Path.extension(addon).toLowerCase()) {
|
||||
case 'zip':
|
||||
addon = Path.withoutExtension(addon);
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var data:AddonInfo = {
|
||||
name: addon,
|
||||
path: path + addon
|
||||
};
|
||||
|
||||
if (addon.startsWith("[LOW]")) _lowPriorityAddons.insert(0, data);
|
||||
else if (addon.startsWith("[HIGH]")) _highPriorityAddons.insert(0, data);
|
||||
else _noPriorityAddons.insert(0, data);
|
||||
}
|
||||
}
|
||||
|
||||
for (addon in _lowPriorityAddons)
|
||||
loadLib(addon.path, ltrim(addon.name, "[LOW]"));
|
||||
|
||||
if (ModsFolder.currentModFolder != null)
|
||||
loadLib(ModsFolder.modsPath + ModsFolder.currentModFolder, ModsFolder.currentModFolder);
|
||||
|
||||
for (addon in _noPriorityAddons)
|
||||
loadLib(addon.path, addon.name);
|
||||
|
||||
for (addon in _highPriorityAddons)
|
||||
loadLib(addon.path, ltrim(addon.name, "[HIGH]"));
|
||||
#end
|
||||
|
||||
Flags.load();
|
||||
@@ -65,14 +109,10 @@ class MainState extends FlxState {
|
||||
EventsData.reloadEvents();
|
||||
TitleState.initialized = false;
|
||||
|
||||
if(Framerate.isLoaded)
|
||||
if (Framerate.isLoaded)
|
||||
Framerate.instance.reload();
|
||||
|
||||
if (Flags.DISABLE_BETA_WARNING_SCREEN || betaWarningShown)
|
||||
FlxG.switchState(new TitleState());
|
||||
else
|
||||
FlxG.switchState(new BetaWarningState());
|
||||
betaWarningShown = true;
|
||||
FlxG.switchState(new TitleState());
|
||||
|
||||
#if sys
|
||||
CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN);
|
||||
|
||||
@@ -13,5 +13,5 @@ class CodenameBuildField extends TextField {
|
||||
}
|
||||
|
||||
public function reload()
|
||||
text = 'Codename Engine ${Flags.RELEASE_CYCLE}\n${Flags.COMMIT_MESSAGE}';
|
||||
text = '${Flags.VERSION_MESSAGE}\n${Flags.COMMIT_MESSAGE}';
|
||||
}
|
||||
|
||||
@@ -49,6 +49,25 @@ class SystemInfo extends FramerateCategory {
|
||||
if (osName != "")
|
||||
osInfo = '${osName} ${osVersion}'.trim();
|
||||
}
|
||||
#elseif windows
|
||||
var windowsCurrentVersionPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
|
||||
var buildNumber = Std.parseInt(RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "CurrentBuildNumber"));
|
||||
var edition = RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "ProductName");
|
||||
|
||||
var lcuKey = "WinREVersion"; // Last Cumulative Update Key On Older Windows Versions
|
||||
if (buildNumber >= 22000) { // Windows 11 Initial Release Build Number
|
||||
edition = edition.replace("Windows 10", "Windows 11");
|
||||
lcuKey = "LCUVer"; // Last Cumulative Update Key On Windows 11
|
||||
}
|
||||
|
||||
var lcuVersion = RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, lcuKey);
|
||||
|
||||
osInfo = edition;
|
||||
|
||||
if (lcuVersion != null && lcuVersion != "")
|
||||
osInfo += ' ${lcuVersion}';
|
||||
else if (lime.system.System.platformVersion != null && lime.system.System.platformVersion != "")
|
||||
osInfo += ' ${lime.system.System.platformVersion}';
|
||||
#else
|
||||
if (lime.system.System.platformLabel != null && lime.system.System.platformLabel != "" && lime.system.System.platformVersion != null && lime.system.System.platformVersion != "")
|
||||
osInfo = '${lime.system.System.platformLabel.replace(lime.system.System.platformVersion, "").trim()} ${lime.system.System.platformVersion}';
|
||||
@@ -58,10 +77,7 @@ class SystemInfo extends FramerateCategory {
|
||||
|
||||
try {
|
||||
#if windows
|
||||
var process = new HiddenProcess("wmic", ["cpu", "get", "name"]);
|
||||
if (process.exitCode() != 0) throw 'Could not fetch CPU information';
|
||||
|
||||
cpuName = process.stdout.readAll().toString().trim().split("\n")[1].trim();
|
||||
cpuName = RegistryUtil.get(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString");
|
||||
#elseif mac
|
||||
var process = new HiddenProcess("sysctl -a | grep brand_string"); // Somehow this isn't able to use the args but it still works
|
||||
if (process.exitCode() != 0) throw 'Could not fetch CPU information';
|
||||
|
||||
@@ -425,9 +425,13 @@ class CoolUtil
|
||||
if (Assets.exists(infoPath)) {
|
||||
var musicInfo = IniUtil.parseAsset(infoPath, [
|
||||
"BPM" => null,
|
||||
"TimeSignature" => Flags.DEFAULT_BEATS_PER_MEASURE + "/" + Flags.DEFAULT_STEPS_PER_BEAT
|
||||
"TimeSignature" => Flags.DEFAULT_BEATS_PER_MEASURE + "/" + Flags.DEFAULT_STEPS_PER_BEAT,
|
||||
"LoopTime" => '${Flags.DEFAULT_LOOP_TIME}'
|
||||
]);
|
||||
|
||||
if (FlxG.sound.music != null)
|
||||
FlxG.sound.music.loopTime = Std.parseFloat(musicInfo["LoopTime"]) * 1000;
|
||||
|
||||
var timeSignParsed:Array<Null<Float>> = musicInfo["TimeSignature"] == null ? [] : [for(s in musicInfo["TimeSignature"].split("/")) Std.parseFloat(s)];
|
||||
var beatsPerMeasure:Float = Flags.DEFAULT_BEATS_PER_MEASURE;
|
||||
var stepsPerBeat:Int = Flags.DEFAULT_STEPS_PER_BEAT;
|
||||
|
||||
@@ -123,7 +123,7 @@ class MemoryUtil {
|
||||
public static function getMemType():String {
|
||||
#if windows
|
||||
var memoryMap:Map<Int, String> = [
|
||||
0 => "Unknown",
|
||||
0 => null,
|
||||
1 => "Other",
|
||||
2 => "DRAM",
|
||||
3 => "Synchronous DRAM",
|
||||
@@ -162,9 +162,9 @@ class MemoryUtil {
|
||||
];
|
||||
var memoryOutput:Int = -1;
|
||||
|
||||
var process = new HiddenProcess("wmic", ["memorychip", "get", "SMBIOSMemoryType"]);
|
||||
var process = new HiddenProcess("powershell", ["-Command", "Get-CimInstance Win32_PhysicalMemory | Select-Object -ExpandProperty SMBIOSMemoryType" ]);
|
||||
if (process.exitCode() == 0) memoryOutput = Std.int(Std.parseFloat(process.stdout.readAll().toString().trim().split("\n")[1]));
|
||||
if (memoryOutput != -1) return memoryMap[memoryOutput];
|
||||
if (memoryOutput != -1) return memoryMap[memoryOutput] == null ? 'Unknown ($memoryOutput)' : memoryMap[memoryOutput];
|
||||
#elseif mac
|
||||
var process = new HiddenProcess("system_profiler", ["SPMemoryDataType"]);
|
||||
var reg = ~/Type: (.+)/;
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package funkin.backend.utils;
|
||||
|
||||
enum abstract RegistryHive(Int) {
|
||||
var HKEY_CLASSES_ROOT = 0x80000000;
|
||||
var HKEY_CURRENT_USER = 0x80000001;
|
||||
var HKEY_LOCAL_MACHINE = 0x80000002;
|
||||
var HKEY_USERS = 0x80000003;
|
||||
var HKEY_CURRENT_CONFIG = 0x80000005;
|
||||
}
|
||||
#if windows
|
||||
@:cppFileCode('
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
')
|
||||
#end
|
||||
class RegistryUtil {
|
||||
#if windows
|
||||
@:functionCode('
|
||||
HKEY hKey;
|
||||
LONG result;
|
||||
DWORD dataSize = 0;
|
||||
DWORD dataType = 0;
|
||||
|
||||
std::wstring subkey = std::wstring(key.wchar_str());
|
||||
std::wstring valname = std::wstring(string.wchar_str());
|
||||
|
||||
result = RegOpenKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, KEY_READ, &hKey);
|
||||
if (result != ERROR_SUCCESS) return null();
|
||||
|
||||
result = RegQueryValueExW(hKey, valname.c_str(), NULL, &dataType, NULL, &dataSize);
|
||||
if (result != ERROR_SUCCESS || dataSize == 0) {
|
||||
RegCloseKey(hKey);
|
||||
return null();
|
||||
}
|
||||
|
||||
std::vector<wchar_t> buffer(dataSize / sizeof(wchar_t));
|
||||
result = RegQueryValueExW(hKey, valname.c_str(), NULL, NULL, (LPBYTE)buffer.data(), &dataSize);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
return ::String(buffer.data());
|
||||
}
|
||||
return null();
|
||||
')
|
||||
#end
|
||||
public static function get(hive:RegistryHive, key:String, string:String):Null<String>
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#if windows
|
||||
@:functionCode('
|
||||
HKEY hKey;
|
||||
LONG result;
|
||||
|
||||
std::wstring subkey = std::wstring(key.wchar_str());
|
||||
std::wstring valname = std::wstring(string.wchar_str());
|
||||
std::wstring data = std::wstring(value.wchar_str());
|
||||
|
||||
result = RegCreateKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
|
||||
if (result != ERROR_SUCCESS) return false;
|
||||
|
||||
result = RegSetValueExW(hKey, valname.c_str(), 0, REG_SZ, (const BYTE*)data.c_str(), (DWORD)((data.length() + 1) * sizeof(wchar_t)));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return result == ERROR_SUCCESS;
|
||||
')
|
||||
#end
|
||||
public static function set(hive:RegistryHive, key:String, string:String, value:String):Bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if windows
|
||||
@:functionCode('
|
||||
HKEY hKey;
|
||||
LONG result;
|
||||
|
||||
std::wstring subkey = std::wstring(key.wchar_str());
|
||||
std::wstring valname = std::wstring(string.wchar_str());
|
||||
|
||||
result = RegOpenKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, KEY_READ, &hKey);
|
||||
if (result != ERROR_SUCCESS) return false;
|
||||
|
||||
DWORD dataType = 0;
|
||||
result = RegQueryValueExW(hKey, valname.c_str(), NULL, &dataType, NULL, NULL);
|
||||
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return result == ERROR_SUCCESS;
|
||||
')
|
||||
#end
|
||||
public static function exists(hive:RegistryHive, key:String, string:String):Bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if windows
|
||||
@:functionCode('
|
||||
HKEY hKey;
|
||||
LONG result;
|
||||
|
||||
std::wstring subkey = std::wstring(key.wchar_str());
|
||||
std::wstring valname = std::wstring(string.wchar_str());
|
||||
|
||||
result = RegOpenKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, KEY_SET_VALUE, &hKey);
|
||||
if (result != ERROR_SUCCESS) return false;
|
||||
|
||||
result = RegDeleteValueW(hKey, valname.c_str());
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return result == ERROR_SUCCESS;
|
||||
')
|
||||
#end
|
||||
public static function delete(hive:RegistryHive, key:String, string:String):Bool {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -114,12 +114,13 @@ class XMLUtil {
|
||||
* @param parentFolder The parent folder
|
||||
* @param defaultAnimType The default animation type
|
||||
*/
|
||||
public static function loadSpriteFromXML(spr:FunkinSprite, node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT):FunkinSprite {
|
||||
public static function loadSpriteFromXML(spr:FunkinSprite, node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT, loadGraphic:Bool = true):FunkinSprite {
|
||||
if (parentFolder == null) parentFolder = "";
|
||||
|
||||
spr.name = node.getAtt("name");
|
||||
spr.antialiasing = true;
|
||||
spr.loadSprite(Paths.image('$parentFolder${node.getAtt("sprite").getDefault(spr.name)}', null, true));
|
||||
if (loadGraphic)
|
||||
spr.loadSprite(Paths.image('$parentFolder${node.getAtt("sprite").getDefault(spr.name)}', null, true));
|
||||
|
||||
spr.spriteAnimType = defaultAnimType;
|
||||
if (node.has.type) {
|
||||
@@ -234,10 +235,10 @@ class XMLUtil {
|
||||
* @param cl The class to create (advanced)
|
||||
* @param args The arguments to pass to the class (advanced)
|
||||
*/
|
||||
public static inline function createSpriteFromXML(node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT, ?cl:Class<FunkinSprite>, ?args:Array<Dynamic>):FunkinSprite {
|
||||
public static inline function createSpriteFromXML(node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT, ?cl:Class<FunkinSprite>, ?args:Array<Dynamic>, loadGraphic:Bool = true):FunkinSprite {
|
||||
if(cl == null) cl = FunkinSprite;
|
||||
if(args == null) args = [];
|
||||
return loadSpriteFromXML(Type.createInstance(cl, args), node, parentFolder, defaultAnimType);
|
||||
return loadSpriteFromXML(Type.createInstance(cl, args), node, parentFolder, defaultAnimType, loadGraphic);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package funkin.backend.week;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.week.WeekData.WeekCharacter;
|
||||
import funkin.backend.week.WeekData;
|
||||
import haxe.xml.Access;
|
||||
|
||||
class Week {
|
||||
public static function loadWeek(weekName:String, loadCharactersData:Bool = true):WeekData {
|
||||
var week:Access = null;
|
||||
try week = new Access(Xml.parse(Assets.getText(Paths.xml('weeks/weeks/$weekName'))).firstElement())
|
||||
catch(e) Logs.trace('Cannot parse week "$weekName.xml": ${Std.string(e)}', ERROR);
|
||||
|
||||
if (week == null) return null;
|
||||
if (!week.has.name) {
|
||||
Logs.trace('Week "${weekName}" has no name attribute', WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
var weekObj:WeekData = {
|
||||
xml: week,
|
||||
name: week.att.name,
|
||||
id: weekName,
|
||||
sprite: week.getAtt('sprite').getDefault(weekName),
|
||||
chars: [null, null, null],
|
||||
songs: [],
|
||||
difficulties: ['easy', 'normal', 'hard']
|
||||
};
|
||||
|
||||
var weekName = weekObj.name;
|
||||
for (k => song in week.nodes.song) {
|
||||
if (song == null) continue;
|
||||
try {
|
||||
var name = song.innerData.trim();
|
||||
if (name == "") {
|
||||
Logs.trace('Song at index ${k} in week $weekName has no name. Skipping...', WARNING);
|
||||
continue;
|
||||
}
|
||||
weekObj.songs.push({
|
||||
name: name,
|
||||
hide: song.getAtt('hide').getDefault('false') == "true",
|
||||
displayName: song.getAtt('displayName')
|
||||
});
|
||||
} catch(e) {
|
||||
Logs.trace('Song at index ${k} in week $weekName cannot contain any other XML nodes in its name.', WARNING);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (weekObj.songs.length <= 0) {
|
||||
Logs.trace('Week $weekName has no songs.', WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
var diffNodes = week.nodes.difficulty;
|
||||
if (diffNodes.length > 0) {
|
||||
var diffs:Array<String> = [for (e in diffNodes) if (e.has.name) e.att.name];
|
||||
if (diffs.length > 0) weekObj.difficulties = diffs;
|
||||
}
|
||||
|
||||
if (week.has.chars) for (k => e in week.att.chars.split(",")) {
|
||||
var trim = e.trim();
|
||||
weekObj.chars[k] = (trim == "" || e == "none" || e == "null") ? null : (loadCharactersData ? loadWeekCharacter(trim) : {name: trim});
|
||||
}
|
||||
|
||||
return weekObj;
|
||||
}
|
||||
|
||||
public static function loadWeekCharacter(charName:String):WeekCharacter {
|
||||
var char:Access = null;
|
||||
try char = new Access(Xml.parse(Assets.getText(Paths.xml('weeks/characters/$charName'))).firstElement())
|
||||
catch(e) Logs.trace('Cannot parse character "$charName.xml": ${Std.string(e)}', ERROR);
|
||||
if (char == null) return null;
|
||||
|
||||
return {
|
||||
xml: char,
|
||||
name: charName,
|
||||
spritePath: Paths.image(char.getAtt('sprite').getDefault('menus/storymenu/characters/${charName}')),
|
||||
scale: Std.parseFloat(char.getAtt('scale')).getDefault(1),
|
||||
offset: FlxPoint.get(
|
||||
Std.parseFloat(char.getAtt('x')).getDefault(0),
|
||||
Std.parseFloat(char.getAtt('y')).getDefault(0)
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package funkin.backend.week;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import haxe.xml.Access;
|
||||
|
||||
typedef WeekData = {
|
||||
var ?xml:Access;
|
||||
var name:String; // name SHOULD NOT be used for loading week highscores, its just the name on the right side of the week, remember that next time!! - Nex
|
||||
var id:String; // id IS instead for saving and loading!! - Nex
|
||||
var sprite:String;
|
||||
var chars:Array<WeekCharacter>;
|
||||
var songs:Array<WeekSong>;
|
||||
var difficulties:Array<String>;
|
||||
}
|
||||
|
||||
typedef WeekCharacter = {
|
||||
var ?xml:Access;
|
||||
var name:String;
|
||||
var ?spritePath:String;
|
||||
var ?scale:Float;
|
||||
var ?offset:FlxPoint;
|
||||
// var frames:FlxFramesCollection;
|
||||
}
|
||||
|
||||
typedef WeekSong = {
|
||||
var name:String;
|
||||
var hide:Bool;
|
||||
var ?displayName:String;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import funkin.options.*;
|
||||
class EditorTreeMenu extends TreeMenu {
|
||||
public var bg:FlxBackdrop;
|
||||
public var bgType:String = "default";
|
||||
public var bgMovement:FlxPoint = new FlxPoint();
|
||||
|
||||
public override function create() {
|
||||
super.create();
|
||||
@@ -16,16 +17,16 @@ class EditorTreeMenu extends TreeMenu {
|
||||
bg = new FlxBackdrop();
|
||||
bg.loadGraphic(Paths.image('editors/bgs/${bgType}'));
|
||||
bg.antialiasing = true;
|
||||
setBackgroundRotation(-5);
|
||||
add(bg);
|
||||
}
|
||||
|
||||
public inline function setBackgroundRotation(rotation:Float) {
|
||||
bg.rotation = rotation;
|
||||
bg.velocity.set(85, 0).degrees = bg.rotation;
|
||||
}
|
||||
|
||||
public override function exit() {
|
||||
FlxG.switchState(new MainMenuState());
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
bg.x += elapsed * 125;
|
||||
bg.y += elapsed * 125;
|
||||
}
|
||||
}
|
||||
@@ -600,7 +600,7 @@ class Charter extends UIState {
|
||||
// Just for now until i add event stacking -lunar
|
||||
try {__relinkUndos();}
|
||||
catch (e) {Logs.trace('Failed to relink undos: ${Std.string(e)}', ERROR);}
|
||||
|
||||
|
||||
__applyPlaytestInfo();
|
||||
}
|
||||
|
||||
@@ -1291,8 +1291,11 @@ class Charter extends UIState {
|
||||
for(id=>str in strumLines.members)
|
||||
if (str != null) str.y = strumlineInfoBG.y;
|
||||
|
||||
strumlineAddButton.x = 0;
|
||||
strumlineAddButton.y = strumlineInfoBG.y;
|
||||
strumlineLockButton.y = strumlineInfoBG.y;
|
||||
|
||||
strumlineLockButton.text.visible = strumlineLockButton.button.selectable = strumlineLockButton.button.visible = strumLines.members.length > 0;
|
||||
}
|
||||
|
||||
var zoom(default, set):Float = 0;
|
||||
@@ -1347,7 +1350,7 @@ class Charter extends UIState {
|
||||
#if sys
|
||||
CoolUtil.safeSaveFile(
|
||||
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/meta.json',
|
||||
Json.stringify(PlayState.SONG.meta == null ? {} : PlayState.SONG.meta, null, Flags.JSON_PRETTY_PRINT)
|
||||
PlayState.SONG.meta == null ? null : Chart.makeMetaSaveable(PlayState.SONG.meta)
|
||||
);
|
||||
#else
|
||||
_file_meta_saveas(_);
|
||||
@@ -1355,7 +1358,7 @@ class Charter extends UIState {
|
||||
}
|
||||
|
||||
function _file_meta_saveas(_) {
|
||||
openSubState(new SaveSubstate(Json.stringify(PlayState.SONG.meta == null ? {} : PlayState.SONG.meta, null, Flags.JSON_PRETTY_PRINT), { // always pretty print meta
|
||||
openSubState(new SaveSubstate(PlayState.SONG.meta == null ? null : Chart.makeMetaSaveable(PlayState.SONG.meta), { // always pretty print meta
|
||||
defaultSaveFile: 'meta.json'
|
||||
}));
|
||||
}
|
||||
@@ -1650,7 +1653,7 @@ class Charter extends UIState {
|
||||
t.icon = (Options.charterLowDetailWaveforms = !Options.charterLowDetailWaveforms) ? 1 : 0;
|
||||
for (shader in waveformHandler.waveShaders) shader.data.lowDetail.value = [Options.charterLowDetailWaveforms];
|
||||
}
|
||||
|
||||
|
||||
inline function _snap_increasesnap(_) changequant(1);
|
||||
inline function _snap_decreasesnap(_) changequant(-1);
|
||||
inline function _snap_resetsnap(_) setquant(16);
|
||||
|
||||
@@ -85,7 +85,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
coopAllowedCheckbox = new UICheckbox(opponentModeCheckbox.x + 150 + 26, opponentModeCheckbox.y, "Co-op Mode", metadata.coopAllowed);
|
||||
add(coopAllowedCheckbox);
|
||||
|
||||
colorWheel = new UIColorwheel(iconTextBox.x, coopAllowedCheckbox.y, metadata.parsedColor);
|
||||
colorWheel = new UIColorwheel(iconTextBox.x, coopAllowedCheckbox.y, metadata.color);
|
||||
add(colorWheel);
|
||||
addLabelOn(colorWheel, "Color");
|
||||
|
||||
@@ -151,8 +151,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
color: colorWheel.curColorString,
|
||||
parsedColor: colorWheel.curColor,
|
||||
color: colorWheel.curColor,
|
||||
opponentModeAllowed: opponentModeCheckbox.checked,
|
||||
coopAllowed: coopAllowedCheckbox.checked,
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import funkin.backend.chart.Chart;
|
||||
import funkin.backend.chart.ChartData.ChartMetaData;
|
||||
import funkin.backend.chart.ChartData;
|
||||
import funkin.backend.system.framerate.Framerate;
|
||||
@@ -40,7 +41,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
}));
|
||||
#end
|
||||
optionsTree.add(new OptionsScreen(s.name, "Select a difficulty to continue.", list));
|
||||
}, s.parsedColor.getDefault(0xFFFFFFFF))
|
||||
}, s.color.getDefault(0xFFFFFFFF))
|
||||
];
|
||||
|
||||
#if sys
|
||||
@@ -114,7 +115,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
sys.FileSystem.createDirectory('$songFolder/charts');
|
||||
|
||||
// Save Files
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(creation.meta, Flags.JSON_PRETTY_PRINT));
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Chart.makeMetaSaveable(creation.meta));
|
||||
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Flags.SOUND_EXT}', creation.instBytes);
|
||||
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Flags.SOUND_EXT}', creation.voicesBytes);
|
||||
|
||||
@@ -137,7 +138,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
FlxG.state.openSubState(new ChartCreationScreen(saveChart));
|
||||
}));
|
||||
optionsTree.insert(1, new OptionsScreen(creation.meta.name, "Select a difficulty to continue.", list));
|
||||
}, creation.meta.parsedColor.getDefault(0xFFFFFFFF));
|
||||
}, creation.meta.color.getDefault(0xFFFFFFFF));
|
||||
|
||||
// Add to List
|
||||
freeplayList.songs.insert(0, creation.meta);
|
||||
@@ -171,7 +172,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
var meta = Json.parse(sys.io.File.getContent('$songFolder/meta.json'));
|
||||
if (meta.difficulties != null && !meta.difficulties.contains(name)) {
|
||||
meta.difficulties.push(name);
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(meta));
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Chart.makeMetaSaveable(meta));
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
@@ -58,8 +58,8 @@ class CharterStrumlineButton extends UISprite {
|
||||
|
||||
super.update(elapsed);
|
||||
|
||||
UIState.state.updateSpriteRect(button);
|
||||
if(UIState.state.curContextMenu == null && UIState.state.isOverlapping(button, button.__rect)) {
|
||||
if (UIState.state.curContextMenu == null && UIState.state.isOverlapping(button, button.__rect) && button.visible) {
|
||||
UIState.state.updateSpriteRect(button);
|
||||
buttonScale.set(0.95, 0.95);
|
||||
if (FlxG.mouse.justPressed && onClick != null) {
|
||||
onClick();
|
||||
|
||||
@@ -405,8 +405,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
color: colorWheel.curColorString,
|
||||
parsedColor: colorWheel.curColor,
|
||||
color: colorWheel.curColor,
|
||||
opponentModeAllowed: opponentModeCheckbox.checked,
|
||||
coopAllowed: coopAllowedCheckbox.checked,
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()],
|
||||
|
||||
@@ -222,8 +222,21 @@ class HealthIcon extends FunkinSprite
|
||||
}
|
||||
|
||||
var animName = 'from-${node.get("from")}-to-${node.get("to")}';
|
||||
if (node.exists("offsetX") || node.exists("offsetY"))
|
||||
addOffset(animName, Std.parseFloat(node.get("offsetX")).getDefault(0), Std.parseFloat(node.get("offsetY")).getDefault(0));
|
||||
|
||||
var offsetX:Float = 0;
|
||||
var offsetY:Float = 0;
|
||||
if (node.exists("offsetX"))
|
||||
offsetX = Std.parseFloat(node.get("offsetX")).getDefault(0);
|
||||
else if (node.exists("offsetx"))
|
||||
offsetX = Std.parseFloat(node.get("offsetx")).getDefault(0);
|
||||
|
||||
if (node.exists("offsetY"))
|
||||
offsetY = Std.parseFloat(node.get("offsetY")).getDefault(0);
|
||||
else if (node.exists("offsety"))
|
||||
offsetY = Std.parseFloat(node.get("offsety")).getDefault(0);
|
||||
|
||||
addOffset(animName, offsetX, offsetY);
|
||||
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), false); // don't allow looping for transitions
|
||||
if (animateAtlas == null && animation.exists(animName))
|
||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||
@@ -257,7 +270,13 @@ class HealthIcon extends FunkinSprite
|
||||
|
||||
addOffset(animName, offsetX, offsetY);
|
||||
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), node.get("looped").getDefault("true").toLowerCase() == "true");
|
||||
var looped:Bool = false;
|
||||
if (node.exists("looped"))
|
||||
looped = node.get("looped").toLowerCase() == "true";
|
||||
else if (node.exists("loop"))
|
||||
looped = node.get("loop").toLowerCase() == "true";
|
||||
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), looped);
|
||||
if (animateAtlas == null && animation.exists(animName))
|
||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||
case "step":
|
||||
|
||||
+16
-20
@@ -151,7 +151,9 @@ class Note extends FlxSprite
|
||||
case 0:
|
||||
animation.addByPrefix('scroll', 'purple0');
|
||||
animation.addByPrefix('hold', 'purple hold piece');
|
||||
animation.addByPrefix('holdend', 'pruple end hold');
|
||||
animation.addByPrefix("holdend", "pruple end hold");
|
||||
if (animation.exists("holdend") != true) // null or false
|
||||
animation.addByPrefix('holdend', 'purple hold end');
|
||||
case 1:
|
||||
animation.addByPrefix('scroll', 'blue0');
|
||||
animation.addByPrefix('hold', 'blue hold piece');
|
||||
@@ -272,30 +274,22 @@ class Note extends FlxSprite
|
||||
public function updateSustain(strum:Strum) {
|
||||
var scrollSpeed = strum.getScrollSpeed(this);
|
||||
|
||||
var len = 0.45 * CoolUtil.quantize(scrollSpeed, 100);
|
||||
|
||||
if (nextSustain != null && lastScrollSpeed != scrollSpeed) {
|
||||
// is long sustain
|
||||
if (lastScrollSpeed != scrollSpeed) {
|
||||
lastScrollSpeed = scrollSpeed;
|
||||
|
||||
scale.y = (sustainLength * len) / frameHeight;
|
||||
updateHitbox();
|
||||
scale.y += gapFix / frameHeight;
|
||||
if (nextSustain != null) {
|
||||
scale.y = (sustainLength * 0.45 * scrollSpeed) / frameHeight;
|
||||
updateHitbox();
|
||||
scale.y += gapFix / frameHeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasGoodHit) return;
|
||||
var t = FlxMath.bound((Conductor.songPosition - strumTime) / (height) * len, 0, 1);
|
||||
var swagRect = this.clipRect == null ? new FlxRect() : this.clipRect;
|
||||
swagRect.x = 0;
|
||||
swagRect.y = t * frameHeight;
|
||||
swagRect.width = frameWidth;
|
||||
swagRect.height = frameHeight;
|
||||
|
||||
setClipRect(swagRect);
|
||||
updateSustainClip();
|
||||
}
|
||||
|
||||
public inline function setClipRect(rect:FlxRect) {
|
||||
this.clipRect = rect;
|
||||
public function updateSustainClip() if (wasGoodHit) {
|
||||
var t = FlxMath.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1);
|
||||
var rect = clipRect == null ? FlxRect.get() : clipRect;
|
||||
clipRect = rect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t));
|
||||
}
|
||||
|
||||
@:noCompletion
|
||||
@@ -311,5 +305,7 @@ class Note extends FlxSprite
|
||||
|
||||
public override function destroy() {
|
||||
super.destroy();
|
||||
|
||||
clipRect = FlxDestroyUtil.put(clipRect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import funkin.editors.charter.CharterSelection;
|
||||
import funkin.game.SplashHandler;
|
||||
import funkin.game.cutscenes.*;
|
||||
import funkin.menus.*;
|
||||
import funkin.menus.StoryMenuState.WeekData;
|
||||
import funkin.backend.week.WeekData;
|
||||
import funkin.savedata.FunkinSave;
|
||||
import haxe.io.Path;
|
||||
|
||||
@@ -1322,16 +1322,8 @@ class PlayState extends MusicBeatState
|
||||
if (updateRatingStuff != null)
|
||||
updateRatingStuff();
|
||||
|
||||
if (canAccessDebugMenus) {
|
||||
if (chartingMode && FlxG.keys.justPressed.SEVEN) {
|
||||
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, false));
|
||||
}
|
||||
/*if (FlxG.keys.justPressed.F5) {
|
||||
Logs.warn('Reloading scripts...', "PlayState");
|
||||
scripts.reload();
|
||||
Logs.warn('Song scripts successfully reloaded.', GREEN, "PlayState");
|
||||
}*/
|
||||
}
|
||||
if (canAccessDebugMenus && chartingMode && FlxG.keys.justPressed.SEVEN)
|
||||
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, false));
|
||||
|
||||
if (doIconBop)
|
||||
for (icon in iconArray)
|
||||
@@ -1642,6 +1634,7 @@ class PlayState extends MusicBeatState
|
||||
*/
|
||||
public function endSong():Void
|
||||
{
|
||||
endingSong = true;
|
||||
gameAndCharsCall("onSongEnd");
|
||||
canPause = false;
|
||||
inst.volume = 0;
|
||||
@@ -2103,7 +2096,7 @@ class PlayState extends MusicBeatState
|
||||
public static function loadWeek(weekData:WeekData, ?difficulty:String) {
|
||||
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
|
||||
storyWeek = weekData;
|
||||
storyPlaylist = [for(e in weekData.songs) e.name];
|
||||
storyPlaylist = [for (e in weekData.songs) e.name];
|
||||
isStoryMode = true;
|
||||
campaignScore = 0;
|
||||
campaignMisses = 0;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package funkin.game;
|
||||
|
||||
class Splash extends FunkinSprite
|
||||
{
|
||||
/**
|
||||
* The current splash strum
|
||||
* WARNING: It can be null
|
||||
*/
|
||||
public var strum:Null<Strum>;
|
||||
|
||||
/**
|
||||
* Shortcut to `strum.ID`
|
||||
* WARNING: It can be null
|
||||
*/
|
||||
public var strumID:Null<Int>;
|
||||
|
||||
public static function copyFrom(source:Splash):Splash
|
||||
{
|
||||
var spr = new Splash();
|
||||
@:privateAccess {
|
||||
spr.setPosition(source.x, source.y);
|
||||
spr.frames = source.frames;
|
||||
if (source.animateAtlas != null && source.atlasPath != null)
|
||||
spr.loadSprite(source.atlasPath);
|
||||
spr.animation.copyFrom(source.animation);
|
||||
spr.visible = source.visible;
|
||||
spr.alpha = source.alpha;
|
||||
spr.antialiasing = source.antialiasing;
|
||||
spr.scale.set(source.scale.x, source.scale.y);
|
||||
spr.scrollFactor.set(source.scrollFactor.x, source.scrollFactor.y);
|
||||
spr.skew.set(source.skew.x, source.skew.y);
|
||||
spr.transformMatrix = source.transformMatrix;
|
||||
spr.matrixExposed = source.matrixExposed;
|
||||
spr.zoomFactor = source.zoomFactor;
|
||||
spr.animOffsets = source.animOffsets.copy();
|
||||
}
|
||||
return spr;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package funkin.game;
|
||||
|
||||
import haxe.xml.Access;
|
||||
|
||||
class SplashGroup extends FlxTypedGroup<FunkinSprite> {
|
||||
class SplashGroup extends FlxTypedGroup<Splash> {
|
||||
/**
|
||||
* Whenever the splash group has successfully loaded or not.
|
||||
*/
|
||||
@@ -46,7 +46,7 @@ class SplashGroup extends FlxTypedGroup<FunkinSprite> {
|
||||
}
|
||||
|
||||
function createSplash(imagePath:String) {
|
||||
var splash = new FunkinSprite();
|
||||
var splash = new Splash();
|
||||
splash.antialiasing = true;
|
||||
splash.active = splash.visible = false;
|
||||
splash.loadSprite(Paths.image(imagePath));
|
||||
@@ -56,7 +56,7 @@ class SplashGroup extends FlxTypedGroup<FunkinSprite> {
|
||||
return splash;
|
||||
}
|
||||
|
||||
function setupAnims(xml:Access, splash:FunkinSprite) {
|
||||
function setupAnims(xml:Access, splash:Splash) {
|
||||
for(strum in xml.nodes.strum) {
|
||||
var id:Null<Int> = Std.parseInt(strum.att.id);
|
||||
if (id != null) {
|
||||
@@ -85,12 +85,14 @@ class SplashGroup extends FlxTypedGroup<FunkinSprite> {
|
||||
};
|
||||
}
|
||||
|
||||
function pregenerateSplashes(splash:FunkinSprite) {
|
||||
function pregenerateSplashes(splash:Splash) {
|
||||
// make 7 additional splashes
|
||||
for(i in 0...7) {
|
||||
var spr = FunkinSprite.copyFrom(splash);
|
||||
var spr = Splash.copyFrom(splash);
|
||||
spr.animation.finishCallback = function(name:String) {
|
||||
spr.active = spr.visible = false;
|
||||
spr.strum = null;
|
||||
spr.strumID = null;
|
||||
};
|
||||
add(spr);
|
||||
}
|
||||
@@ -103,11 +105,14 @@ class SplashGroup extends FlxTypedGroup<FunkinSprite> {
|
||||
return animationNames[id][FlxG.random.int(0, animationNames[id].length - 1)];
|
||||
}
|
||||
|
||||
var __splash:FunkinSprite;
|
||||
var __splash:Splash;
|
||||
public function showOnStrum(strum:Strum) {
|
||||
if (!valid) return null;
|
||||
__splash = recycle();
|
||||
|
||||
__splash.strum = strum;
|
||||
__splash.strumID = strum.ID;
|
||||
|
||||
__splash.cameras = strum.lastDrawCameras;
|
||||
__splash.setPosition(strum.x + ((strum.width - __splash.width) / 2), strum.y + ((strum.height - __splash.height) / 2));
|
||||
__splash.active = __splash.visible = true;
|
||||
|
||||
@@ -2,7 +2,7 @@ package funkin.game;
|
||||
|
||||
import funkin.backend.scripting.events.splash.*;
|
||||
|
||||
class SplashHandler extends FlxTypedGroup<FunkinSprite> {
|
||||
class SplashHandler extends FlxTypedGroup<Splash> {
|
||||
/**
|
||||
* Map containing all of the splashes group.
|
||||
*/
|
||||
|
||||
@@ -45,7 +45,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
for (k=>e in stageSprites) script.set(k, e);
|
||||
|
||||
public function prepareInfos(node:Access)
|
||||
return XMLImportedScriptInfo.prepareInfos(node, PlayState.instance.scripts, (infos) -> xmlImportedScripts.push(infos));
|
||||
return XMLImportedScriptInfo.prepareInfos(node, PlayState.instance != null ? PlayState.instance.scripts : null, (infos) -> xmlImportedScripts.push(infos));
|
||||
|
||||
public function new(stage:String, ?state:FlxState) {
|
||||
super();
|
||||
@@ -111,17 +111,28 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
case "box" | "solid":
|
||||
if (!node.has.name || !node.has.width || !node.has.height) continue;
|
||||
|
||||
var spr = new FlxSprite(
|
||||
var spr = new FunkinSprite(
|
||||
(node.has.x) ? Std.parseFloat(node.att.x).getDefault(0) : 0,
|
||||
(node.has.y) ? Std.parseFloat(node.att.y).getDefault(0) : 0
|
||||
);
|
||||
|
||||
(node.name == "solid" ? spr.makeSolid : spr.makeGraphic)(
|
||||
// just to make sure, its better to apply these before it gets inside of xmlUtil (because of mainly updateHitbox i guess), so im removing them before it gets passed - Nex
|
||||
var toRemove = ["x", "y", "width", "height", "color"];
|
||||
var isSolid = node.name == "solid";
|
||||
|
||||
(isSolid ? spr.makeSolid : spr.makeGraphic)(
|
||||
Std.parseInt(node.att.width),
|
||||
Std.parseInt(node.att.height),
|
||||
(node.has.color) ? CoolUtil.getColorFromDynamic(node.att.color) : -1
|
||||
);
|
||||
|
||||
if (isSolid) toRemove.push("updateHitbox"); // makesolid already calls updateHitbox - Nex
|
||||
for (a in toRemove) node.x.remove(a);
|
||||
XMLUtil.loadSpriteFromXML(spr, node, "", NONE, false);
|
||||
|
||||
if (!node.has.zoomfactor && PlayState.instance != null)
|
||||
spr.initialZoom = PlayState.instance.defaultCamZoom;
|
||||
|
||||
stageSprites.set(node.getAtt("name"), spr);
|
||||
state.add(spr);
|
||||
spr;
|
||||
@@ -363,4 +374,4 @@ typedef StageCharPosInfo = {
|
||||
var y:Float;
|
||||
var flip:Bool;
|
||||
var scroll:Float;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
|
||||
if (cpu && __updateNote_event.__autoCPUHit && !daNote.avoid && !daNote.wasGoodHit && daNote.strumTime < __updateNote_songPos) PlayState.instance.goodNoteHit(this, daNote);
|
||||
|
||||
if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + (daNote.sustainLength) < __updateNote_songPos) {
|
||||
if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + daNote.sustainLength < __updateNote_songPos) {
|
||||
deleteNote(daNote);
|
||||
return;
|
||||
}
|
||||
@@ -247,8 +247,9 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
var __notePerStrum:Array<Note> = [];
|
||||
|
||||
function __inputProcessPressed(note:Note) {
|
||||
if (__pressed[note.strumID] && note.isSustainNote && note.canBeHit && !note.wasGoodHit) {
|
||||
if (__pressed[note.strumID] && note.isSustainNote && note.strumTime < __updateNote_songPos && !note.wasGoodHit) {
|
||||
PlayState.instance.goodNoteHit(this, note);
|
||||
note.updateSustainClip();
|
||||
}
|
||||
}
|
||||
function __inputProcessJustPressed(note:Note) {
|
||||
|
||||
@@ -200,7 +200,7 @@ class DialogueCutscene extends ScriptedCutscene {
|
||||
if (curMusic != null && !curMusic.persist) curMusic.destroy();
|
||||
|
||||
super.destroy();
|
||||
cutscene = null;
|
||||
if (cutscene == this) cutscene = null;
|
||||
FlxG.cameras.remove(dialogueCamera);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ class FreeplayState extends MusicBeatState
|
||||
scoreText.x = coopText.x = scoreBG.x + 4;
|
||||
diffText.x = Std.int(scoreBG.x + ((scoreBG.width - diffText.width) / 2));
|
||||
|
||||
interpColor.fpsLerpTo(songs[curSelected].parsedColor, 0.0625);
|
||||
interpColor.fpsLerpTo(songs[curSelected].color, 0.0625);
|
||||
bg.color = interpColor.color;
|
||||
|
||||
#if PRELOAD_ALL
|
||||
@@ -453,16 +453,10 @@ class FreeplaySonglist {
|
||||
|
||||
public function getSongsFromSource(source:funkin.backend.assets.AssetsLibraryList.AssetSource, useTxt:Bool = true) {
|
||||
var path:String = Paths.txt('freeplaySonglist');
|
||||
var songsFound:Array<String> = [];
|
||||
if (useTxt && Paths.assetsTree.existsSpecific(path, "TEXT", source)) {
|
||||
songsFound = CoolUtil.coolTextFile(Paths.txt('freeplaySonglist'));
|
||||
} else {
|
||||
songsFound = Paths.getFolderDirectories('songs', false, source);
|
||||
}
|
||||
var songsFound:Array<String> = useTxt && Paths.assetsTree.existsSpecific(path, "TEXT", source) ? CoolUtil.coolTextFile(path) : Paths.getFolderDirectories('songs', false, source);
|
||||
|
||||
if (songsFound.length > 0) {
|
||||
for(s in songsFound)
|
||||
songs.push(Chart.loadChartMeta(s, Flags.DEFAULT_DIFFICULTY, source == MODS));
|
||||
for (s in songsFound) songs.push(Chart.loadChartMeta(s, Flags.DEFAULT_DIFFICULTY, source == MODS));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -485,4 +479,4 @@ class FreeplaySonglist {
|
||||
|
||||
return songList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,15 @@ class ModSwitchMenu extends MusicBeatSubstate {
|
||||
var alphabets:FlxTypedGroup<Alphabet>;
|
||||
var curSelected:Int = 0;
|
||||
|
||||
var subCam:FlxCamera;
|
||||
|
||||
public override function create() {
|
||||
super.create();
|
||||
|
||||
camera = subCam = new FlxCamera();
|
||||
subCam.bgColor = 0;
|
||||
FlxG.cameras.add(subCam, false);
|
||||
|
||||
var bg = new FlxSprite(0, 0).makeSolid(FlxG.width, FlxG.height, 0xFF000000);
|
||||
bg.updateHitbox();
|
||||
bg.scrollFactor.set();
|
||||
@@ -66,5 +72,12 @@ class ModSwitchMenu extends MusicBeatSubstate {
|
||||
}
|
||||
alphabets.members[curSelected].alpha = 1;
|
||||
}
|
||||
|
||||
override function destroy() {
|
||||
super.destroy();
|
||||
|
||||
if (FlxG.cameras.list.contains(subCam))
|
||||
FlxG.cameras.remove(subCam);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
@@ -5,17 +5,20 @@ import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import funkin.backend.FunkinText;
|
||||
import funkin.backend.scripting.events.CancellableEvent;
|
||||
import funkin.backend.scripting.events.menu.MenuChangeEvent;
|
||||
import funkin.backend.scripting.events.menu.storymenu.*;
|
||||
import funkin.backend.scripting.events.CancellableEvent;
|
||||
import funkin.backend.week.*;
|
||||
import funkin.savedata.FunkinSave;
|
||||
import haxe.io.Path;
|
||||
import haxe.xml.Access;
|
||||
|
||||
class StoryMenuState extends MusicBeatState {
|
||||
public var characters:Map<String, Access> = [];
|
||||
public var characters:Map<String, WeekData.WeekCharacter> = [];
|
||||
public var weeks:Array<WeekData> = [];
|
||||
public var weekList:StoryWeeklist;
|
||||
|
||||
// yes it supports parameters - Nex
|
||||
public var scoreMessage:String = "WEEK SCORE:{0}";
|
||||
@@ -33,7 +36,6 @@ class StoryMenuState extends MusicBeatState {
|
||||
public var blackBar:FlxSprite;
|
||||
|
||||
public var weekBG:FlxSprite;
|
||||
public var defColor:String = "#F9CF51";
|
||||
public var interpColor:FlxInterpolateColor;
|
||||
|
||||
public var lerpScore:Float = 0;
|
||||
@@ -64,7 +66,7 @@ class StoryMenuState extends MusicBeatState {
|
||||
weekTitle.alpha = 0.7;
|
||||
|
||||
weekBG = new FlxSprite(0, 56).makeSolid(FlxG.width, 400, 0xFFFFFFFF);
|
||||
weekBG.color = weeks.length > 0 ? weeks[0].bgColor : FlxColor.fromString(defColor);
|
||||
weekBG.color = weeks.length > 0 ? weeks[0].bgColor : Flags.DEFAULT_WEEK_COLOR;
|
||||
weekBG.updateHitbox();
|
||||
|
||||
weekSprites = new FlxTypedGroup<MenuItem>();
|
||||
@@ -92,19 +94,18 @@ class StoryMenuState extends MusicBeatState {
|
||||
tracklist.color = 0xFFE55777;
|
||||
|
||||
add(weekSprites);
|
||||
for(e in [blackBar, scoreText, weekTitle, weekBG, tracklist]) {
|
||||
e.antialiasing = true;
|
||||
for (e in [blackBar, scoreText, weekTitle, weekBG, tracklist]) {
|
||||
e.scrollFactor.set();
|
||||
add(e);
|
||||
}
|
||||
|
||||
add(characterSprites = new FlxTypedGroup<FunkinSprite>());
|
||||
|
||||
for(i=>week in weeks) {
|
||||
for (i=>week in weeks) {
|
||||
var spr:MenuItem = new MenuItem(0, (i * 120) + 480, 'menus/storymenu/weeks/${week.sprite}');
|
||||
weekSprites.add(spr);
|
||||
|
||||
for(e in week.difficulties) {
|
||||
for (e in week.difficulties) {
|
||||
var le = e.toLowerCase();
|
||||
if (difficultySprites[le] == null) {
|
||||
var diffSprite = new FlxSprite(leftArrow.x + leftArrow.width, leftArrow.y);
|
||||
@@ -163,6 +164,12 @@ class StoryMenuState extends MusicBeatState {
|
||||
weekBG.color = interpColor.color;
|
||||
}
|
||||
|
||||
public override function beatHit(curBeat:Int) {
|
||||
super.beatHit(curBeat);
|
||||
if (characterSprites != null) // reason why I wanted to use a MusicBeatGroup, but eh, whatever - Nex
|
||||
characterSprites.forEachAlive(function(spr) spr.beatHit(curBeat));
|
||||
}
|
||||
|
||||
public function goBack() {
|
||||
var event = event("onGoBack", new CancellableEvent());
|
||||
if (!event.cancelled)
|
||||
@@ -181,13 +188,17 @@ class StoryMenuState extends MusicBeatState {
|
||||
e.targetY = k - curWeek;
|
||||
e.alpha = k == curWeek ? 1.0 : 0.6;
|
||||
}
|
||||
tracklist.text = 'TRACKS\n\n${[for(e in weeks[curWeek].songs) if (!e.hide) e.name].join('\n')}';
|
||||
tracklist.text = 'TRACKS\n\n${[for(e in weeks[curWeek].songs) if (!e.hide) e.displayName.getDefault(e.name).toUpperCase()].join('\n')}';
|
||||
weekTitle.text = weeks[curWeek].name.getDefault("");
|
||||
|
||||
if(characterSprites != null) for(i in 0...3) {
|
||||
var curChar:FunkinSprite; var newChar:Access = characters[weeks[curWeek].chars[i]];
|
||||
if(newChar == null) modifyCharacterAt(i);
|
||||
else if((curChar = characterSprites.members[i]) == null || newChar.getAtt("name") != curChar.name) modifyCharacterAt(i, newChar);
|
||||
if (characterSprites != null) for (i in 0...3) {
|
||||
var char = weeks[curWeek].chars[i];
|
||||
var curChar:FunkinSprite = null;
|
||||
var newChar = null;
|
||||
|
||||
if (char == null || (newChar = characters[char.name]) == null) modifyCharacterAt(i);
|
||||
else if ((curChar = cast characterSprites.members[i]) == null || newChar.name != curChar.name) modifyCharacterAt(i, newChar); // forcing the sprites to be FunkinSprite basically - Nex
|
||||
trace(newChar != null ? newChar.name : null, curChar != null ? curChar.name : null);
|
||||
}
|
||||
|
||||
changeDifficulty(0, true);
|
||||
@@ -195,27 +206,6 @@ class StoryMenuState extends MusicBeatState {
|
||||
MemoryUtil.clearMinor();
|
||||
}
|
||||
|
||||
public function modifyCharacterAt(i:Int, ?node:Access):FunkinSprite {
|
||||
var old = characterSprites.members[i];
|
||||
if(old != null) {
|
||||
characterSprites.remove(old);
|
||||
old.destroy();
|
||||
}
|
||||
|
||||
if(node == null) return null;
|
||||
var curChar:FunkinSprite = XMLUtil.createSpriteFromXML(node, "", BEAT);
|
||||
curChar.offset.x += curChar.x; curChar.offset.y += curChar.y;
|
||||
curChar.setPosition((FlxG.width * 0.25) * (1 + i) - 150, 70);
|
||||
if(characterSprites != null) characterSprites.insert(i, curChar); // Making so many null checks abt this group just in case if mods destroy it - Nex
|
||||
curChar.playAnim("idle", true, DANCE);
|
||||
return curChar;
|
||||
}
|
||||
|
||||
public override function beatHit(curBeat:Int) {
|
||||
super.beatHit(curBeat);
|
||||
if(characterSprites != null) characterSprites.forEachAlive(function(spr) spr.beatHit(curBeat));
|
||||
}
|
||||
|
||||
var __oldDiffName = null;
|
||||
public function changeDifficulty(change:Int, force:Bool = false) {
|
||||
if (change == 0 && !force) return;
|
||||
@@ -244,122 +234,45 @@ class StoryMenuState extends MusicBeatState {
|
||||
}
|
||||
|
||||
public function loadXMLs() {
|
||||
// CoolUtil.coolTextFile(Paths.txt('freeplaySonglist'));
|
||||
var weeks:Array<String> = [];
|
||||
|
||||
switch(Flags.WEEKS_LIST_MOD_MODE) {
|
||||
case 'prepend':
|
||||
getWeeksFromSource(weeks, MODS);
|
||||
getWeeksFromSource(weeks, SOURCE);
|
||||
case 'append':
|
||||
getWeeksFromSource(weeks, SOURCE);
|
||||
getWeeksFromSource(weeks, MODS);
|
||||
default /*case 'override'*/:
|
||||
if (getWeeksFromSource(weeks, MODS))
|
||||
getWeeksFromSource(weeks, SOURCE);
|
||||
}
|
||||
|
||||
for(k=>weekName in weeks) {
|
||||
var week:Access = null;
|
||||
try {
|
||||
week = new Access(Xml.parse(Assets.getText(Paths.xml('weeks/weeks/$weekName'))).firstElement());
|
||||
} catch(e) {
|
||||
Logs.trace('Cannot parse week "$weekName.xml": ${Std.string(e)}`', ERROR);
|
||||
}
|
||||
|
||||
if (week == null) continue;
|
||||
|
||||
if (!week.has.name) {
|
||||
Logs.trace('Story Menu: Week at index ${k} has no name. Skipping...', WARNING);
|
||||
continue;
|
||||
}
|
||||
var weekObj:WeekData = {
|
||||
name: week.att.name,
|
||||
id: weekName,
|
||||
sprite: week.getAtt('sprite').getDefault(weekName),
|
||||
chars: [null, null, null],
|
||||
songs: [],
|
||||
difficulties: ['easy', 'normal', 'hard'],
|
||||
bgColor: FlxColor.fromString(week.getAtt("bgColor").getDefault(defColor))
|
||||
};
|
||||
|
||||
var diffNodes = week.nodes.difficulty;
|
||||
if (diffNodes.length > 0) {
|
||||
var diffs:Array<String> = [];
|
||||
for(e in diffNodes) {
|
||||
if (e.has.name) diffs.push(e.att.name);
|
||||
}
|
||||
if (diffs.length > 0)
|
||||
weekObj.difficulties = diffs;
|
||||
}
|
||||
|
||||
if (week.has.chars) {
|
||||
for(k=>e in week.att.chars.split(",")) {
|
||||
if (e.trim() == "" || e == "none" || e == "null")
|
||||
weekObj.chars[k] = null;
|
||||
else {
|
||||
addCharacter(weekObj.chars[k] = e.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
for(k2=>song in week.nodes.song) {
|
||||
if (song == null) continue;
|
||||
try {
|
||||
var name = song.innerData.trim();
|
||||
if (name == "") {
|
||||
Logs.trace('Story Menu: Song at index ${k2} in week ${weekObj.name} has no name. Skipping...', WARNING);
|
||||
continue;
|
||||
}
|
||||
weekObj.songs.push({
|
||||
name: name,
|
||||
hide: song.getAtt('hide').getDefault('false') == "true"
|
||||
});
|
||||
} catch(e) {
|
||||
Logs.trace('Story Menu: Song at index ${k2} in week ${weekObj.name} cannot contain any other XML nodes in its name.', WARNING);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (weekObj.songs.length <= 0) {
|
||||
Logs.trace('Story Menu: Week ${weekObj.name} has no songs. Skipping...', WARNING);
|
||||
continue;
|
||||
}
|
||||
this.weeks.push(weekObj);
|
||||
}
|
||||
weekList = StoryWeeklist.get(true, false); // will only load week files AND NOT characters too (we will load them later only if needed)!! - Nex
|
||||
weeks = weekList.weeks;
|
||||
for (week in weeks) for (char in week.chars) if (char != null)
|
||||
addCharacter(char.name);
|
||||
}
|
||||
|
||||
public function addCharacter(charName:String) {
|
||||
var char:Access = null;
|
||||
try {
|
||||
char = new Access(Xml.parse(Assets.getText(Paths.xml('weeks/characters/$charName'))).firstElement());
|
||||
} catch(e) {
|
||||
Logs.trace('Story Menu: Cannot parse character "$charName.xml": ${Std.string(e)}`', ERROR);
|
||||
}
|
||||
public function addCharacter(char:OneOfTwo<String, WeekData.WeekCharacter>) {
|
||||
// better to use unsafe casts for going fast - Nex
|
||||
var charObj:WeekData.WeekCharacter = null;
|
||||
var charName:String;
|
||||
|
||||
if(char != null && characters[charName] == null) {
|
||||
if(!char.x.exists("name")) char.x.set("name", charName);
|
||||
if(!char.x.exists("sprite")) char.x.set("sprite", 'menus/storymenu/characters/${charName}');
|
||||
if(!char.x.exists("beatInterval")) char.x.set("beatInterval", "1");
|
||||
if(!char.x.exists("updateHitbox")) char.x.set("updateHitbox", "true");
|
||||
characters[charName] = char;
|
||||
}
|
||||
charName = char is String ? cast char : (charObj = cast char).name;
|
||||
if (characters[charName] != null) return; // will load only if it can be saved inside the map - Nex
|
||||
characters[charName] = charObj == null ? Week.loadWeekCharacter(charName) : charObj;
|
||||
}
|
||||
|
||||
public function getWeeksFromSource(weeks:Array<String>, source:funkin.backend.assets.AssetsLibraryList.AssetSource) {
|
||||
var path:String = Paths.txt('freeplaySonglist');
|
||||
var weeksFound:Array<String> = [];
|
||||
if (Paths.assetsTree.existsSpecific(path, "TEXT", source)) {
|
||||
var trim = "";
|
||||
weeksFound = CoolUtil.coolTextFile(Paths.txt('weeks/weeks'));
|
||||
} else {
|
||||
weeksFound = [for(c in Paths.getFolderContent('data/weeks/weeks/', false, source)) if (Path.extension(c).toLowerCase() == "xml") Path.withoutExtension(c)];
|
||||
}
|
||||
public function modifyCharacterAt(i:Int, ?data:WeekData.WeekCharacter):FunkinSprite {
|
||||
var curChar:FunkinSprite = null;
|
||||
|
||||
if (weeksFound.length > 0) {
|
||||
for(s in weeksFound)
|
||||
weeks.push(s);
|
||||
return false;
|
||||
if (characterSprites != null) {
|
||||
var old = characterSprites.members[i];
|
||||
if (old != null) {
|
||||
characterSprites.remove(old);
|
||||
old.destroy();
|
||||
}
|
||||
|
||||
trace(data);
|
||||
if (data != null) {
|
||||
curChar = XMLUtil.createSpriteFromXML(data.xml, "", BEAT);
|
||||
curChar.offset.x += curChar.x; curChar.offset.y += curChar.y;
|
||||
curChar.setPosition((FlxG.width * 0.25) * (1 + i) - 150, 70);
|
||||
curChar.playAnim("idle", true, DANCE);
|
||||
characterSprites.insert(i, curChar);
|
||||
} else {
|
||||
//characterSprites.members[i] = null; // cant add nulls to flxgroups, so - Nex
|
||||
characterSprites.insert(i, new FunkinSprite()).visible = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return curChar;
|
||||
}
|
||||
|
||||
public function selectWeek() {
|
||||
@@ -369,7 +282,7 @@ class StoryMenuState extends MusicBeatState {
|
||||
canSelect = false;
|
||||
CoolUtil.playMenuSFX(CONFIRM);
|
||||
|
||||
if(characterSprites != null)
|
||||
if (characterSprites != null)
|
||||
characterSprites.forEachAlive(function(spr) spr.playAnim("confirm", true, LOCK));
|
||||
|
||||
PlayState.loadWeek(event.week, event.difficulty);
|
||||
@@ -382,21 +295,6 @@ class StoryMenuState extends MusicBeatState {
|
||||
}
|
||||
}
|
||||
|
||||
typedef WeekData = {
|
||||
var name:String; // name SHOULD NOT be used for loading week highscores, its just the name on the right side of the week, remember that next time!! - Nex
|
||||
var id:String; // id IS instead for saving and loading!! - Nex
|
||||
var sprite:String;
|
||||
var chars:Array<String>;
|
||||
var songs:Array<WeekSong>;
|
||||
var difficulties:Array<String>;
|
||||
var bgColor:FlxColor;
|
||||
}
|
||||
|
||||
typedef WeekSong = {
|
||||
var name:String;
|
||||
var hide:Bool;
|
||||
}
|
||||
|
||||
class MenuItem extends FlxSprite
|
||||
{
|
||||
public var targetY:Float = 0;
|
||||
@@ -438,3 +336,42 @@ class MenuItem extends FlxSprite
|
||||
color = (time % 0.1 > 0.05) ? FlxColor.WHITE : 0xFF33ffff;
|
||||
}
|
||||
}
|
||||
|
||||
class StoryWeeklist {
|
||||
public var weeks:Array<WeekData> = [];
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function getWeeksFromSource(source:funkin.backend.assets.AssetsLibraryList.AssetSource, useTxt:Bool = true, loadCharactersData:Bool = true) {
|
||||
var path:String = Paths.txt('weeks/weeks');
|
||||
var weeksFound:Array<String> = useTxt && Paths.assetsTree.existsSpecific(path, "TEXT", source) ? CoolUtil.coolTextFile(path) :
|
||||
[for (c in Paths.getFolderContent('data/weeks/weeks/', false, source)) if (Path.extension(c).toLowerCase() == "xml") Path.withoutExtension(c)];
|
||||
|
||||
if (weeksFound.length > 0) {
|
||||
for (w in weeksFound) {
|
||||
var week = Week.loadWeek(w, loadCharactersData);
|
||||
if (week != null) weeks.push(week);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function get(useTxt:Bool = true, loadCharactersData:Bool = true) {
|
||||
var weekList = new StoryWeeklist();
|
||||
|
||||
switch(Flags.WEEKS_LIST_MOD_MODE) {
|
||||
case 'prepend':
|
||||
weekList.getWeeksFromSource(MODS, useTxt, loadCharactersData);
|
||||
weekList.getWeeksFromSource(SOURCE, useTxt, loadCharactersData);
|
||||
case 'append':
|
||||
weekList.getWeeksFromSource(SOURCE, useTxt, loadCharactersData);
|
||||
weekList.getWeeksFromSource(MODS, useTxt, loadCharactersData);
|
||||
default /*case 'override'*/:
|
||||
if (weekList.getWeeksFromSource(MODS, useTxt, loadCharactersData))
|
||||
weekList.getWeeksFromSource(SOURCE, useTxt, loadCharactersData);
|
||||
}
|
||||
|
||||
return weekList;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package funkin.menus.credits;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.backend.assets.AssetsLibraryList.AssetSource;
|
||||
import funkin.backend.system.github.GitHubContributor.CreditsGitHubContributor;
|
||||
import funkin.options.OptionsScreen;
|
||||
import funkin.options.TreeMenu;
|
||||
import funkin.backend.system.github.GitHubContributor.CreditsGitHubContributor;
|
||||
import funkin.options.type.*;
|
||||
import haxe.xml.Access;
|
||||
import flixel.util.FlxColor;
|
||||
|
||||
class CreditsMain extends TreeMenu {
|
||||
var bg:FlxSprite;
|
||||
@@ -21,21 +22,17 @@ class CreditsMain extends TreeMenu {
|
||||
bg.antialiasing = true;
|
||||
add(bg);
|
||||
|
||||
var xmlPath = Paths.xml('config/credits');
|
||||
for(source in [funkin.backend.assets.AssetsLibraryList.AssetSource.SOURCE, funkin.backend.assets.AssetsLibraryList.AssetSource.MODS]) {
|
||||
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) {
|
||||
var access:Access = null;
|
||||
try {
|
||||
access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT", source)));
|
||||
} catch(e) {
|
||||
Logs.trace('[CreditsMain] Error while parsing credits.xml: ${Std.string(e)}', ERROR);
|
||||
}
|
||||
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
|
||||
var xmlPath = Paths.xml('config/credits/LIB_$i');
|
||||
|
||||
if (access != null)
|
||||
for(c in parseCreditsFromXML(access, source))
|
||||
items.push(c);
|
||||
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT")) {
|
||||
var access:Access = null;
|
||||
try access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT")))
|
||||
catch(e) Logs.trace('[CreditsMain] Error while parsing credits.xml: ${Std.string(e)}', ERROR);
|
||||
if (access != null) for (c in parseCreditsFromXML(access)) items.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
items.push(new TextOption("Codename Engine >", "Select this to see all the contributors of the engine!", function() {
|
||||
optionsTree.add(Type.createInstance(CreditsCodename, []));
|
||||
}));
|
||||
@@ -52,7 +49,7 @@ class CreditsMain extends TreeMenu {
|
||||
/**
|
||||
* XML STUFF
|
||||
*/
|
||||
public function parseCreditsFromXML(xml:Access, source:funkin.backend.assets.AssetsLibraryList.AssetSource):Array<OptionType> {
|
||||
public function parseCreditsFromXML(xml:Access, source:AssetSource = BOTH):Array<OptionType> {
|
||||
var credsMenus:Array<OptionType> = [];
|
||||
|
||||
for(node in xml.elements) {
|
||||
|
||||
@@ -73,12 +73,16 @@ class Options
|
||||
public static var charterAutoSavesSeparateFolder:Bool = false;
|
||||
|
||||
/**
|
||||
* PLAYER 1 CONTROLS
|
||||
*/
|
||||
* PLAYER 1 CONTROLS
|
||||
*/
|
||||
|
||||
// Notes
|
||||
public static var P1_NOTE_LEFT:Array<FlxKey> = [A];
|
||||
public static var P1_NOTE_DOWN:Array<FlxKey> = [S];
|
||||
public static var P1_NOTE_UP:Array<FlxKey> = [W];
|
||||
public static var P1_NOTE_RIGHT:Array<FlxKey> = [D];
|
||||
|
||||
// Menus
|
||||
public static var P1_LEFT:Array<FlxKey> = [A];
|
||||
public static var P1_DOWN:Array<FlxKey> = [S];
|
||||
public static var P1_UP:Array<FlxKey> = [W];
|
||||
@@ -86,16 +90,28 @@ class Options
|
||||
public static var P1_ACCEPT:Array<FlxKey> = [ENTER];
|
||||
public static var P1_BACK:Array<FlxKey> = [BACKSPACE];
|
||||
public static var P1_PAUSE:Array<FlxKey> = [ENTER];
|
||||
|
||||
// Misc
|
||||
public static var P1_RESET:Array<FlxKey> = [R];
|
||||
public static var P1_SWITCHMOD:Array<FlxKey> = [TAB];
|
||||
public static var P1_VOLUME_UP:Array<FlxKey> = [];
|
||||
public static var P1_VOLUME_DOWN:Array<FlxKey> = [];
|
||||
public static var P1_VOLUME_MUTE:Array<FlxKey> = [];
|
||||
|
||||
// Debugs
|
||||
public static var P1_DEBUG_RELOAD:Array<FlxKey> = [F5];
|
||||
|
||||
/**
|
||||
* PLAYER 2 CONTROLS (ALT)
|
||||
*/
|
||||
* PLAYER 2 CONTROLS (ALT)
|
||||
*/
|
||||
|
||||
// Notes
|
||||
public static var P2_NOTE_LEFT:Array<FlxKey> = [LEFT];
|
||||
public static var P2_NOTE_DOWN:Array<FlxKey> = [DOWN];
|
||||
public static var P2_NOTE_UP:Array<FlxKey> = [UP];
|
||||
public static var P2_NOTE_RIGHT:Array<FlxKey> = [RIGHT];
|
||||
|
||||
// Menus
|
||||
public static var P2_LEFT:Array<FlxKey> = [LEFT];
|
||||
public static var P2_DOWN:Array<FlxKey> = [DOWN];
|
||||
public static var P2_UP:Array<FlxKey> = [UP];
|
||||
@@ -103,16 +119,28 @@ class Options
|
||||
public static var P2_ACCEPT:Array<FlxKey> = [SPACE];
|
||||
public static var P2_BACK:Array<FlxKey> = [ESCAPE];
|
||||
public static var P2_PAUSE:Array<FlxKey> = [ESCAPE];
|
||||
|
||||
// Misc
|
||||
public static var P2_RESET:Array<FlxKey> = [];
|
||||
public static var P2_SWITCHMOD:Array<FlxKey> = [];
|
||||
public static var P2_VOLUME_UP:Array<FlxKey> = [NUMPADPLUS];
|
||||
public static var P2_VOLUME_DOWN:Array<FlxKey> = [NUMPADMINUS];
|
||||
public static var P2_VOLUME_MUTE:Array<FlxKey> = [NUMPADZERO];
|
||||
|
||||
// Debugs
|
||||
public static var P2_DEBUG_RELOAD:Array<FlxKey> = [];
|
||||
|
||||
/**
|
||||
* SOLO GETTERS
|
||||
*/
|
||||
* SOLO GETTERS
|
||||
*/
|
||||
|
||||
// Notes
|
||||
public static var SOLO_NOTE_LEFT(get, null):Array<FlxKey>;
|
||||
public static var SOLO_NOTE_DOWN(get, null):Array<FlxKey>;
|
||||
public static var SOLO_NOTE_UP(get, null):Array<FlxKey>;
|
||||
public static var SOLO_NOTE_RIGHT(get, null):Array<FlxKey>;
|
||||
|
||||
// Menus
|
||||
public static var SOLO_LEFT(get, null):Array<FlxKey>;
|
||||
public static var SOLO_DOWN(get, null):Array<FlxKey>;
|
||||
public static var SOLO_UP(get, null):Array<FlxKey>;
|
||||
@@ -120,8 +148,16 @@ class Options
|
||||
public static var SOLO_ACCEPT(get, null):Array<FlxKey>;
|
||||
public static var SOLO_BACK(get, null):Array<FlxKey>;
|
||||
public static var SOLO_PAUSE(get, null):Array<FlxKey>;
|
||||
|
||||
// Misc
|
||||
public static var SOLO_RESET(get, null):Array<FlxKey>;
|
||||
public static var SOLO_SWITCHMOD(get, null):Array<FlxKey>;
|
||||
public static var SOLO_VOLUME_UP(get, null):Array<FlxKey>;
|
||||
public static var SOLO_VOLUME_DOWN(get, null):Array<FlxKey>;
|
||||
public static var SOLO_VOLUME_MUTE(get, null):Array<FlxKey>;
|
||||
|
||||
// Debugs
|
||||
public static var SOLO_DEBUG_RELOAD(get, null):Array<FlxKey>;
|
||||
|
||||
public static function load() {
|
||||
if (__save == null) __save = new FlxSave();
|
||||
@@ -150,6 +186,10 @@ class Options
|
||||
PlayerSettings.solo.setKeyboardScheme(Solo);
|
||||
PlayerSettings.player1.setKeyboardScheme(Duo(true));
|
||||
PlayerSettings.player2.setKeyboardScheme(Duo(false));
|
||||
|
||||
FlxG.sound.volumeUpKeys = SOLO_VOLUME_UP;
|
||||
FlxG.sound.volumeDownKeys = SOLO_VOLUME_DOWN;
|
||||
FlxG.sound.muteKeys = SOLO_VOLUME_MUTE;
|
||||
}
|
||||
|
||||
public static function save() {
|
||||
|
||||
@@ -54,36 +54,24 @@ class OptionsMenu extends TreeMenu {
|
||||
if (o.substate != null) {
|
||||
persistentUpdate = false;
|
||||
persistentDraw = true;
|
||||
if (o.substate is MusicBeatSubstate) {
|
||||
openSubState(o.substate);
|
||||
} else {
|
||||
openSubState(Type.createInstance(o.substate, []));
|
||||
}
|
||||
if (o.substate is MusicBeatSubstate) openSubState(o.substate);
|
||||
else openSubState(Type.createInstance(o.substate, []));
|
||||
} else {
|
||||
if (o.state is OptionsScreen) {
|
||||
optionsTree.add(o.state);
|
||||
} else {
|
||||
optionsTree.add(Type.createInstance(o.state, []));
|
||||
}
|
||||
if (o.state is OptionsScreen) optionsTree.add(o.state);
|
||||
else optionsTree.add(Type.createInstance(o.state, []));
|
||||
}
|
||||
})]);
|
||||
|
||||
var xmlPath = Paths.xml("config/options");
|
||||
for(source in [funkin.backend.assets.AssetsLibraryList.AssetSource.SOURCE, funkin.backend.assets.AssetsLibraryList.AssetSource.MODS]) {
|
||||
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) {
|
||||
var access:Access = null;
|
||||
try {
|
||||
access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT", source)));
|
||||
} catch(e) {
|
||||
Logs.trace('Error while parsing options.xml: ${Std.string(e)}', ERROR);
|
||||
}
|
||||
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
|
||||
var xmlPath = Paths.xml('config/options/LIB_$i');
|
||||
|
||||
if (access != null)
|
||||
for(o in parseOptionsFromXML(access))
|
||||
main.add(o);
|
||||
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT")) {
|
||||
var access:Access = null;
|
||||
try access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT")))
|
||||
catch(e) Logs.trace('Error while parsing options.xml: ${Std.string(e)}', ERROR);
|
||||
if (access != null) for (o in parseOptionsFromXML(access)) main.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override function exit() {
|
||||
|
||||
@@ -66,6 +66,23 @@ class KeybindsOptions extends MusicBeatSubstate {
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Volume',
|
||||
settings: [
|
||||
{
|
||||
name: 'Up',
|
||||
control: 'VOLUME_UP'
|
||||
},
|
||||
{
|
||||
name: 'Down',
|
||||
control: 'VOLUME_DOWN'
|
||||
},
|
||||
{
|
||||
name: 'Mute',
|
||||
control: 'VOLUME_MUTE'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Engine',
|
||||
settings: [
|
||||
@@ -74,6 +91,15 @@ class KeybindsOptions extends MusicBeatSubstate {
|
||||
control: 'SWITCHMOD'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'DEBUG',
|
||||
settings: [
|
||||
{
|
||||
name: 'Reload',
|
||||
control: 'DEBUG_RELOAD'
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -162,6 +188,10 @@ class KeybindsOptions extends MusicBeatSubstate {
|
||||
}
|
||||
add(alphabets);
|
||||
add(camFollow);
|
||||
|
||||
FlxG.sound.volumeUpKeys = [];
|
||||
FlxG.sound.volumeDownKeys = [];
|
||||
FlxG.sound.muteKeys = [];
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
@@ -175,10 +205,8 @@ class KeybindsOptions extends MusicBeatSubstate {
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
|
||||
|
||||
if (isSubState) {
|
||||
bg.alpha = lerp(bg.alpha, 0.1, 0.125);
|
||||
} else {
|
||||
if (isSubState) bg.alpha = lerp(bg.alpha, 0.1, 0.125);
|
||||
else {
|
||||
if (curSelected < 4) {
|
||||
if (coloredBG.alpha == 0)
|
||||
coloredBG.color = noteColors[curSelected];
|
||||
@@ -194,11 +222,11 @@ class KeybindsOptions extends MusicBeatSubstate {
|
||||
changeSelection((controls.UP_P ? -1 : 0) + (controls.DOWN_P ? 1 : 0));
|
||||
|
||||
if (controls.BACK) {
|
||||
MusicBeatState.skipTransIn = true;
|
||||
if (isSubState)
|
||||
close();
|
||||
else
|
||||
if (isSubState) close();
|
||||
else {
|
||||
MusicBeatState.skipTransIn = true;
|
||||
FlxG.switchState(new OptionsMenu());
|
||||
}
|
||||
Options.applyKeybinds();
|
||||
Options.save();
|
||||
return;
|
||||
|
||||
@@ -695,7 +695,8 @@ class Sound extends EventDispatcher
|
||||
// var samples = (__buffer.data.length * 8) / (__buffer.channels * __buffer.bitsPerSample);
|
||||
// return Std.int(samples / __buffer.sampleRate * 1000);
|
||||
var samples = (Int64.make(0, __buffer.data.length) * Int64.ofInt(8)) / Int64.ofInt(__buffer.channels * __buffer.bitsPerSample);
|
||||
var value = samples / Int64.ofInt(__buffer.sampleRate) * Int64.ofInt(1000);
|
||||
var div = Int64.divMod(samples * Int64.ofInt(1000), Int64.ofInt(__buffer.sampleRate));
|
||||
var value = (div.quotient + (div.modulus / __buffer.sampleRate));
|
||||
return Int64.toInt(value);
|
||||
}
|
||||
else if (__buffer.__srcVorbisFile != null)
|
||||
|
||||
Reference in New Issue
Block a user