Aghhh variant, variation, whatever

This commit is contained in:
Ralty
2025-08-09 00:31:45 +07:00
parent 6112e2f759
commit 9c7bb8f073
11 changed files with 146 additions and 119 deletions
+2 -2
View File
@@ -128,11 +128,11 @@ class Paths
return scriptPath;
}
static public function chart(song:String, ?difficulty:String):String
static public function chart(song:String, ?difficulty:String, ?variant:String):String
{
difficulty = (difficulty != null ? difficulty : Flags.DEFAULT_DIFFICULTY);
return getPath('songs/$song/charts/$difficulty.json', null);
return getPath('songs/$song/charts/${variant != null ? variant + "/" : ""}$difficulty.json', null);
}
public static function character(character:String):String {
+27 -13
View File
@@ -139,7 +139,8 @@ class Chart {
}
}
if (includeMetaVariations & data.variants.length > 0) for (variant in data.variants) {
data.metas = [];
if (includeMetaVariations && data.variants.length > 0) for (variant in data.variants) {
if (!data.metas.exists(variant) && Assets.exists(Paths.file('songs/$songName/meta-$variant.json')))
data.metas.set(variant, loadChartMeta(songName, variant, fromMods));
}
@@ -147,8 +148,10 @@ class Chart {
return data;
}
public static function parse(songName:String, ?variant:String):ChartData {
var chartPath = Paths.chart(songName, variant);
public static function parse(songName:String, ?difficulty:String, ?variant:String):ChartData {
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
var chartPath = Paths.chart(songName, difficulty, variant);
var base:ChartData = {
strumLines: [],
noteTypes: [],
@@ -162,7 +165,7 @@ class Chart {
fromMods: Paths.assetsTree.existsSpecific(chartPath, "TEXT", MODS)
};
var valid:Bool = true, namePrint = (variant == null || variant == '') ? '$songName' : '$songName ($variant)';
var valid:Bool = true, namePrint = '$songName $difficulty' + ((variant != null && variant != '') ? ' ($variant)' : '');
if (!Assets.exists(chartPath)) {
Logs.error('Chart for song $namePrint at "$chartPath" was not found.');
valid = false;
@@ -256,22 +259,33 @@ class Chart {
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
if (saveSettings == null) saveSettings = {};
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents);
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents && saveSettings.seperateGlobalEvents != true);
#if sys
var songPath = saveSettings.songFolder == null ? 'assets/songs/${chart.meta.name}' : saveSettings.songFolder;
var prefix = 'assets/songs/', assetsRoot = Paths.getAssetsRoot() + '/';
var songPath = saveSettings.songFolder == null ? '${chart.meta.name}' : saveSettings.songFolder, prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null;
var metaPath = '$songPath/meta.json', temp:String;
if ((temp = Paths.assetsTree.getPath(metaPath)) != null) metaPath = temp;
if ((temp = Paths.assetsTree.getPath(prefix + metaPath)) != null) metaPath = temp;
else metaPath = assetsRoot + metaPath;
var chartFolder = saveSettings.folder == null ? ((variant == null || variant == '') ? 'charts' : 'charts/$variant') : saveSettings.folder;
var chartPath = '$songPath/$chartFolder/${difficulty.trim()}.json';
if ((temp = Paths.assetsTree.getPath(chartPath)) != null) chartPath = temp;
if ((temp = Paths.assetsTree.getPath(prefix + chartPath)) != null) chartPath = temp;
else chartPath = assetsRoot + chartPath;
if (saveSettings.saveChart == null || saveSettings.saveChart == true)
CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null));
CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, prettyPrint));
if (filteredChart.meta != null && (saveSettings.overrideExistingMeta || !FileSystem.exists(metaPath)))
CoolUtil.safeSaveFile(metaPath, makeMetaSaveable(filteredChart.meta));
if (saveSettings.overrideExistingMeta || !FileSystem.exists(metaPath))
CoolUtil.safeSaveFile(metaPath, Json.stringify(filterMetaForSaving(chart.meta), null, prettyPrint));
if (saveSettings.seperateGlobalEvents == true) {
var eventsPath = '$songPath/events.json';
if ((temp = Paths.assetsTree.getPath(prefix + eventsPath)) != null) eventsPath = temp;
else eventsPath = assetsRoot + eventsPath;
CoolUtil.safeSaveFile(eventsPath, Json.stringify({events: filterEventsForSaving(chart.events, false, true)}, null, prettyPrint));
}
#end
return filteredChart;
@@ -304,10 +318,10 @@ class Chart {
var data = [];
if (!saveLocalEvents && !saveGlobalEvents) return data;
for (event in chart.events) if ((saveLocalEvents && event.global != true) || (saveGlobalEvents && event.global == true)) {
for (event in events) if ((saveLocalEvents && event.global != true) || (saveGlobalEvents && event.global == true)) {
var copy = Reflect.copy(event);
if (saveLocalEvents ? event.global != true : event.global == true) Reflect.deleteField(copy, "global"); // should NOT delete the field when saving with the local events and the event should have been global - Nex
data.events.push(copy);
data.push(copy);
}
return data;
@@ -9,6 +9,10 @@ final class FreeplaySongSelectEvent extends CancellableEvent {
* Difficulty name
*/
public var difficulty:String;
/**
* Variation Name
*/
public var variant:String;
/**
* Whenever opponent mode is enabled or not.
*/
@@ -43,8 +43,6 @@ class FunkinSaveMacro {
* SAVE FUNCTION
*/
var saveFuncBlocks:Array<Expr> = [for(f in fieldNames) macro $i{saveFieldName}.data.$f = $i{f}];
saveFuncBlocks.push(macro $i{"__flush"}());
saveFuncBlocks.push(macro $i{saveFieldName}.flush());
fields.push({
@@ -60,6 +58,8 @@ class FunkinSaveMacro {
access: [APublic, AStatic]
});
var loadFuncBlocks:Array<Expr> = [for(f in fieldNames) macro if ($i{saveFieldName}.data.$f != null) $i{f} = $i{saveFieldName}.data.$f];
/**
* LOAD FUNCTION
*/
@@ -70,10 +70,7 @@ class FunkinSaveMacro {
args: [],
expr: {
pos: Context.currentPos(),
expr: EBlock([for(f in fieldNames)
macro if ($i{saveFieldName}.data.$f != null)
$i{f} = $i{saveFieldName}.data.$f
, macro $i{"__load"}()])
expr: EBlock(loadFuncBlocks)
}
}),
access: [APublic, AStatic]
+29 -36
View File
@@ -28,6 +28,7 @@ import flixel.util.FlxColor;
class Charter extends UIState {
public static var __song:String;
static var __diff:String;
static var __variant:String;
static var __reload:Bool;
var chart(get, never):ChartData;
@@ -114,11 +115,12 @@ class Charter extends UIState {
private var SONGPOSINFO_BPM = TU.getRaw("songPosInfo.bpm");
private var SONGPOSINFO_TIMESIGNATURE = TU.getRaw("songPosInfo.timeSignature");
public function new(song:String, diff:String, reload:Bool = true) {
public function new(song:String, diff:String, variant:String, reload:Bool = true) {
super();
if (song != null) {
__song = song;
__diff = diff;
__variant = variant;
__reload = reload;
}
}
@@ -578,7 +580,7 @@ class Charter extends UIState {
dataDisplay.screenCenter(Y);
dataDisplay.cameras = [charterCamera]; dataDisplay.x = -dataDisplay.width; add(dataDisplay);*/
DiscordUtil.call("onEditorLoaded", ["Chart Editor", __song + " (" + __diff + ")"]);
DiscordUtil.call("onEditorLoaded", ["Chart Editor", __song + " (" + __diff + ")" + (__variant != null && __variant != "" ? " (" + __variant + ")" : "")]);
}
override function destroy() {
@@ -595,7 +597,7 @@ class Charter extends UIState {
public function loadSong() {
if (__reload) {
EventsData.reloadEvents();
PlayState.loadSong(__song, __diff, false, false);
PlayState.loadSong(__song, __diff, __variant, false, false);
__resetStatics();
}
Conductor.setupSong(PlayState.SONG);
@@ -788,12 +790,13 @@ class Charter extends UIState {
autoSaveTimer = Options.charterAutoSaveTime;
if (!autoSaveNotif.cancelled) {
buildChart();
var songPath:String = '${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}';
if (Options.charterAutoSavesSeparateFolder)
Chart.save(songPath, PlayState.SONG, __autoSaveLocation, {saveMetaInChart: true, saveLocalEvents: true, saveGlobalEvents: true, folder: "autosaves", prettyPrint: Options.editorCharterPrettyPrint});
else // These two chart saves are particular, to avoid any kind of loss, stuff like meta, global and local events will be save all together - Nex
Chart.save(songPath, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: true, saveLocalEvents: true, saveGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint});
Chart.save(PlayState.SONG, __diff.toLowerCase(), __autoSaveLocation, {saveMetaInChart: true, saveLocalEvents: true, seperateGlobalEvents: true, folder: 'autosaves', prettyPrint: Options.editorCharterPrettyPrint});
else
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: true, saveLocalEvents: true, seperateGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint});
FlxG.sound.play(Paths.sound('editors/save'));
undos.save();
}
autoSaveNotif.cancelled = false;
@@ -1476,8 +1479,8 @@ class Charter extends UIState {
public static function saveChart(shouldBuild:Bool = true, withEvents:Bool = true) {
#if sys
FlxG.sound.play(Paths.sound('editors/save'));
saveTo('${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}', !withEvents, shouldBuild);
if (shouldBuild && instance != null) instance.buildChart();
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: false, saveLocalEvents: withEvents, prettyPrint: Options.editorCharterPrettyPrint});
if (undos != null) undos.save();
#else
saveChartAs(shouldBuild, withEvents);
@@ -1493,13 +1496,9 @@ class Charter extends UIState {
public static function saveEvents(shouldBuild:Bool = true) {
#if sys
FlxG.sound.play(Paths.sound('editors/save'));
if (shouldBuild && instance != null) instance.buildChart();
var data = {events: Chart.filterChartForSaving(PlayState.SONG, false, false, true).events};
var path = '${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/events.json';
if (data.events != null && data.events.length > 0) CoolUtil.safeSaveFile(path, Json.stringify(data, null, Options.editorCharterPrettyPrint ? Flags.JSON_PRETTY_PRINT : null));
else if (FileSystem.exists(path)) FileSystem.deleteFile(path); // Instead of replacing with a useless empty file, deletes the file directly - Nex
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveChart: false, seperateGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint});
if (undos != null) undos.save();
#else
saveEventsAs(shouldBuild);
#end
@@ -1507,7 +1506,7 @@ class Charter extends UIState {
public static function saveEventsAs(shouldBuild:Bool = true) {
if (shouldBuild && instance != null) instance.buildChart();
var data = {events: Chart.filterChartForSaving(PlayState.SONG, false, false, true).events};
var data = {events: Chart.filterEventsForSaving(PlayState.SONG.events, false, true)};
saveAs(data, null, Options.editorCharterPrettyPrint ? Flags.JSON_PRETTY_PRINT : null, {
defaultSaveFile: 'events.json'
@@ -1516,12 +1515,8 @@ class Charter extends UIState {
public static function saveMeta(shouldBuild:Bool = true) {
#if sys
FlxG.sound.play(Paths.sound('editors/save'));
if (shouldBuild && instance != null) instance.buildChart();
CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/meta.json',
Json.stringify(PlayState.SONG.meta == null ? {} : Chart.filterChartForSaving(PlayState.SONG, true, false, false).meta, null, Flags.JSON_PRETTY_PRINT)
);
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveChart: false, overrideExistingMeta: true, prettyPrint: true});
#else
saveMetaAs(shouldBuild);
#end
@@ -1545,9 +1540,7 @@ class Charter extends UIState {
}, null, shouldBuild);
}
public static function saveAs(data:Dynamic, ?replacer:(key:Dynamic, value:Dynamic) -> Dynamic, ?space:String, ?options:SaveSubstate.SaveSubstateData, ?saveOptions:Map<String, Bool>, shouldBuild:Bool = true) {
FlxG.sound.play(Paths.sound('editors/save'));
if (shouldBuild && instance != null) instance.buildChart();
public static function saveAs(data:Dynamic, ?replacer:(key:Dynamic, value:Dynamic) -> Dynamic, ?space:String, ?options:SaveSubstate.SaveSubstateData, ?saveOptions:Map<String, Bool>, shouldBuild:Bool = true) { if (shouldBuild && instance != null) instance.buildChart();
var cur = FlxG.state;
while(true) {
if (instance != null || cur.subState == null) return cur.openSubState(new SaveSubstate(Json.stringify(data, replacer, space), options, saveOptions));
@@ -1558,7 +1551,7 @@ class Charter extends UIState {
#if sys
public static function saveTo(path:String, separateEvents:Bool = false, shouldBuild:Bool = true) {
if (shouldBuild && instance != null) instance.buildChart();
Chart.save(path, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, saveLocalEvents: !separateEvents, prettyPrint: Options.editorCharterPrettyPrint});
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: false, saveLocalEvents: !separateEvents, songFolder: path, prettyPrint: Options.editorCharterPrettyPrint});
}
#end
#end
@@ -1570,17 +1563,17 @@ class Charter extends UIState {
else {undos = null; FlxG.switchState(new CharterSelection()); Charter.instance.__clearStatics();}
}
function _file_save_all(_) saveEverything();
function _file_save(_) saveChart();
function _file_saveas(_) saveChartAs();
function _file_events_save(_) saveEvents();
function _file_events_saveas(_) saveEventsAs();
function _file_save_no_events(_) saveChart(true, false);
function _file_saveas_no_events(_) saveChartAs(true, false);
function _file_meta_save(_) saveMeta();
function _file_meta_saveas(_) saveMetaAs();
function _file_saveas_fnflegacy(_) saveLegacyChartAs();
function _file_saveas_psych(_) savePsychChartAs();
function _file_save_all(_) {saveEverything(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_save(_) {saveChart(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas(_) {saveChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_events_save(_) {saveEvents(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_events_saveas(_) {saveEventsAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_save_no_events(_) {saveChart(true, false); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas_no_events(_) {saveChartAs(true, false); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_meta_save(_) {saveMeta(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_meta_saveas(_) {saveMetaAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas_fnflegacy(_) {saveLegacyChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas_psych(_) {savePsychChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _edit_copy(_, playSFX=true) {
if (playSFX) FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_COPY_SOUND));
@@ -26,7 +26,7 @@ class CharterSelectionScreen extends EditorTreeMenuScreen {
public var curSong:ChartMetaData;
inline public function makeChartOption(d:String, name:String):TextOption {
return new TextOption(d, getID('acceptDifficulty'), () -> FlxG.switchState(new Charter(name, d)));
return new TextOption(d, getID('acceptDifficulty'), () -> FlxG.switchState(new Charter(name, d, null)));
}
public function makeSongOption(s:ChartMetaData):IconOption {
+17 -12
View File
@@ -65,6 +65,10 @@ class PlayState extends MusicBeatState
* The selected difficulty name.
*/
public static var difficulty:String = Flags.DEFAULT_DIFFICULTY;
/**
* The selected variation name. (It can be null)
*/
public static var variation:Null<String>;
/**
* Whenever the week is coming from the mods folder or not.
*/
@@ -657,7 +661,7 @@ class PlayState extends MusicBeatState
persistentDraw = true;
if (SONG == null)
SONG = Chart.parse('tutorial', 'normal');
SONG = Chart.parse('tutorial', difficulty = 'normal', variation = null);
scrollSpeed = SONG.scrollSpeed;
@@ -1352,7 +1356,7 @@ class PlayState extends MusicBeatState
updateRatingStuff();
if (canAccessDebugMenus && chartingMode && controls.DEV_ACCESS)
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, false));
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, variation, false));
if (Options.camZoomOnBeat && camZooming) {
var beat = Conductor.getBeats(camZoomingEvery, camZoomingInterval, camZoomingOffset);
@@ -1697,7 +1701,7 @@ class PlayState extends MusicBeatState
if (validScore) {
#if !switch
FunkinSave.setSongHighscore(SONG.meta.name, difficulty, {
FunkinSave.setSongHighscore(SONG.meta.name, difficulty, variation, {
score: songScore,
misses: misses,
accuracy: accuracy,
@@ -1748,16 +1752,16 @@ class PlayState extends MusicBeatState
FlxG.save.flush();
}
else {
Logs.infos('Loading next song (${storyPlaylist[0].toLowerCase()}/$difficulty)', "PlayState");
Logs.infos('Loading next song (${storyPlaylist[0].toLowerCase()}/$difficulty/$variation)', "PlayState");
registerSmoothTransition();
__loadSong(storyPlaylist[0], difficulty);
__loadSong(storyPlaylist[0], difficulty, variation);
FlxG.switchState(new PlayState());
}
}
else if (chartingMode)
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, false));
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, variation, false));
else
FlxG.switchState(new FreeplayState());
}
@@ -2128,7 +2132,7 @@ class PlayState extends MusicBeatState
* @param weekData Week Data
* @param difficulty Week Difficulty
*/
public static function loadWeek(weekData:WeekData, ?difficulty:String) {
public static function loadWeek(weekData:WeekData, ?difficulty:String, ?variation:String) {
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
storyWeek = weekData;
storyPlaylist = [for (e in weekData.songs) e.name];
@@ -2139,7 +2143,7 @@ class PlayState extends MusicBeatState
campaignAccuracyCount = 0;
chartingMode = false;
opponentMode = coopMode = false;
__loadSong(storyPlaylist[0], difficulty);
__loadSong(storyPlaylist[0], difficulty, variation);
}
/**
@@ -2149,13 +2153,13 @@ class PlayState extends MusicBeatState
* @param opponentMode Whenever opponent mode is on
* @param coopMode Whenever co-op mode is on.
*/
public static function loadSong(_name:String, ?_difficulty:String, _opponentMode:Bool = false, _coopMode:Bool = false) {
public static function loadSong(_name:String, ?_difficulty:String, ?_variation:String, _opponentMode:Bool = false, _coopMode:Bool = false) {
if (_difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
isStoryMode = false;
opponentMode = _opponentMode;
chartingMode = false;
coopMode = _coopMode;
__loadSong(_name, _difficulty);
__loadSong(_name, _difficulty, _variation);
}
/**
@@ -2163,12 +2167,13 @@ class PlayState extends MusicBeatState
* @param name Song name
* @param difficulty Song difficulty
*/
public static function __loadSong(_name:String, _difficulty:String) {
public static function __loadSong(_name:String, _difficulty:String, _variation:String) {
difficulty = _difficulty;
variation = _variation;
seenCutscene = false;
deathCounter = 0;
SONG = Chart.parse(_name, _difficulty);
SONG = Chart.parse(_name, _difficulty, _variation);
fromMods = SONG.fromMods;
}
}
+46 -35
View File
@@ -25,9 +25,14 @@ class FreeplayState extends MusicBeatState
public var curSong:Null<ChartMetaData>;
/**
* Current song metadata difficulty
* Current song difficulties
*/
public var curSongDifficulty:Null<String>;
public var curDifficulties:Array<String>;
/**
* songs[curSelected].metas.get(curDiffMetaIndices[curDifficulty])
*/
public var curDiffMetaKeys:Array<String> = [];
/**
* Currently selected song
@@ -117,10 +122,12 @@ class FreeplayState extends MusicBeatState
curSelected = k;
}
}
updateCurSongMeta();
updateCurDifficulties();
updateCurSong();
if (curSong != null) {
for(k=>diff in songs[curSelected].difficulties) {
for(k=>diff in curDifficulties) {
if (diff == Options.freeplayLastDifficulty) {
curDifficulty = k;
}
@@ -257,7 +264,7 @@ class FreeplayState extends MusicBeatState
var dontPlaySongThisFrame = false;
autoplayElapsed += elapsed;
if (!disableAutoPlay && !songInstPlaying && (autoplayElapsed > timeUntilAutoplay)) {
if (curPlayingInst != (curPlayingInst = Paths.inst(curSong.name, curSongDifficulty, curSong.instSuffix))) {
if (curPlayingInst != (curPlayingInst = Paths.inst(curSong.name, curDifficulties[curDifficulty], curSong.instSuffix))) {
var streamed = false;
if (Options.streamedMusic) {
var sound = Assets.getMusic(curPlayingInst, true, false);
@@ -330,9 +337,9 @@ class FreeplayState extends MusicBeatState
public function select() {
updateCoopModes();
if (songs[curSelected].difficulties.length <= 0) return;
if (curDifficulties.length == 0) return;
var event = event("onSelect", EventManager.get(FreeplaySongSelectEvent).recycle(curSong.name, curSongDifficulty, __opponentMode, __coopMode));
var event = event("onSelect", EventManager.get(FreeplaySongSelectEvent).recycle(curSong.name, curDifficulties[curDifficulty], curSong.variant, __opponentMode, __coopMode));
if (event.cancelled) return;
@@ -341,16 +348,17 @@ class FreeplayState extends MusicBeatState
#end
Options.freeplayLastSong = curSong.name;
Options.freeplayLastDifficulty = curSongDifficulty;
Options.freeplayLastDifficulty = curDifficulties[curDifficulty];
Options.freeplayLastVariation = curSong.variant;
PlayState.loadSong(event.song, event.difficulty, event.opponentMode, event.coopMode);
PlayState.loadSong(event.song, event.difficulty, event.variant, event.opponentMode, event.coopMode);
FlxG.switchState(new PlayState());
}
public function convertChart() {
trace('Converting ${curSong.name} (${curSongDifficulty}) to Codename format...');
var chart = Chart.parse(curSong.name, curSongDifficulty);
Chart.save('${Main.pathBack}assets/songs/${curSong.name}', chart, curSongDifficulty);
trace('Converting ${curSong.name} ${curDifficulties[curDifficulty]} ${curSong.variant} to Codename format...');
var chart = Chart.parse(curSong.name, curDifficulties[curDifficulty], curSong.variant);
Chart.save(chart, curDifficulties[curDifficulty], curSong.variant);
}
/**
@@ -358,39 +366,35 @@ class FreeplayState extends MusicBeatState
* @param change How much to change.
* @param force Force the change if `change` is equal to 0
*/
public function changeDiff(change:Int = 0, force:Bool = false)
{
public function changeDiff(change:Int = 0, force:Bool = false) {
if (change == 0 && !force) return;
var song = songs[curSelected];
var validDifficulties = song.difficulties.length > 0;
var event = event("onChangeDiff", EventManager.get(MenuChangeEvent).recycle(curDifficulty, validDifficulties ? FlxMath.wrap(curDifficulty + change, 0, song.difficulties.length-1) : 0, change));
var validDifficulties = curDifficulties.length > 0;
var event = event("onChangeDiff", EventManager.get(MenuChangeEvent).recycle(curDifficulty, validDifficulties ? FlxMath.wrap(curDifficulty + change, 0, curDifficulties.length-1) : 0, change));
if (event.cancelled) {
if (force) updateCurSongMeta();
if (force) updateCurSong();
return;
}
var prevInstSuffix = curSong.instSuffix;
var prevSong = curSong;
curDifficulty = event.value;
updateCurSongMeta();
updateCurSong();
updateScore();
#if PRELOAD_ALL
if (curSong.instSuffix != prevInstSuffix) {
if (curSong != prevSong) {
autoplayElapsed = 0;
songInstPlaying = false;
}
#end
if (song.difficulties.length > 1)
diffText.text = '< ${song.difficulties[curDifficulty].toUpperCase()} >';
else
diffText.text = validDifficulties ? song.difficulties[curDifficulty].toUpperCase() : "-";
var text = validDifficulties ? curDifficulties[curDifficulty].toUpperCase() + (curSong != songs[curSelected] ? ' (${curSong.variant.toUpperCase()})' : '') : '-';
diffText.text = curDifficulties.length > 1 ? '< $text >' : text;
}
function updateScore() {
if (songs[curSelected].difficulties.length <= 0) {
if (curDifficulties.length == 0) {
intendedScore = 0;
return;
}
@@ -398,7 +402,7 @@ class FreeplayState extends MusicBeatState
var changes:Array<HighscoreChange> = [];
if (__coopMode) changes.push(CCoopMode);
if (__opponentMode) changes.push(COpponentMode);
var saveData = FunkinSave.getSongHighscore(curSong.name, curSongDifficulty, changes);
var saveData = FunkinSave.getSongHighscore(curSong.name, curDifficulties[curDifficulty], curSong.variant, changes);
intendedScore = saveData.score;
}
@@ -448,8 +452,7 @@ class FreeplayState extends MusicBeatState
* @param change How much to change
* @param force Force the change, even if `change` is equal to 0.
*/
public function changeSelection(change:Int = 0, force:Bool = false)
{
public function changeSelection(change:Int = 0, force:Bool = false) {
if (change == 0 && !force) return;
var event = event("onChangeSelection", EventManager.get(MenuChangeEvent).recycle(curSelected, FlxMath.wrap(curSelected + change, 0, songs.length-1), change));
@@ -458,6 +461,7 @@ class FreeplayState extends MusicBeatState
curSelected = event.value;
if (event.playMenuSFX) CoolUtil.playMenuSFX(SCROLL, 0.7);
updateCurDifficulties();
changeDiff(0, true);
#if PRELOAD_ALL
@@ -491,13 +495,20 @@ class FreeplayState extends MusicBeatState
}
}
function updateCurSongMeta() {
var song = songs[curSelected];
if (song == null) {
curSong = null;
curSongDifficulty = null;
function updateCurDifficulties() {
curDiffMetaKeys.resize(0);
curDifficulties = songs[curSelected].difficulties.copy();
for (i in 0...curDifficulties.length) curDiffMetaKeys.push(null);
for (variant => meta in songs[curSelected].metas) {
curDifficulties = curDifficulties.concat(meta.difficulties);
for (i in 0...meta.difficulties.length) curDiffMetaKeys.push(variant);
}
else if ((curSong = song.metas.get(curSongDifficulty = song.difficulties[curDifficulty])) == null)
}
function updateCurSong() {
var song = songs[curSelected];
if (song == null) curSong = null;
else if ((curSong = song.metas.get(curDiffMetaKeys[curDifficulty])) == null)
curSong = song;
}
}
+1 -1
View File
@@ -167,7 +167,7 @@ class PauseSubState extends MusicBeatSubstate
case "Change Options":
FlxG.switchState(new OptionsMenu((_) -> FlxG.switchState(new PlayState())));
case "Exit to charter":
FlxG.switchState(new Charter(PlayState.SONG.meta.name, PlayState.difficulty, false));
FlxG.switchState(new Charter(PlayState.SONG.meta.name, PlayState.difficulty, PlayState.variation, false));
case "Exit to menu":
if (PlayState.chartingMode && Charter.undos.unsaved)
game.saveWarn(false);
+1
View File
@@ -73,6 +73,7 @@ class Options
*/
public static var freeplayLastSong:String = null;
public static var freeplayLastDifficulty:String = "normal";
public static var freeplayLastVariation:String = null;
public static var contributors:Array<funkin.backend.system.github.GitHubContributor.CreditsGitHubContributor> = [];
public static var mainDevs:Array<Int> = []; // IDs
public static var lastUpdated:Null<Float>;
+15 -13
View File
@@ -11,14 +11,14 @@ import haxe.Unserializer;
* Just add your save variables the way you would do in the Options.hx file.
* The macro will automatically generate the `flush` and `load` functions.
*/
@:build(funkin.backend.system.macros.FunkinSaveMacro.build("save", "flush", "load"))
@:build(funkin.backend.system.macros.FunkinSaveMacro.build("save", "__flush", "__load"))
class FunkinSave {
@:doNotSave public static var highscores:Map<HighscoreEntry, SongScore> = [];
/**
* ONLY OPEN IF YOU WANT TO EDIT FUNCTIONS RELATED TO SAVING, LOADING OR HIGHSCORES.
*/
#if REGION
@:doNotSave public static var highscores:Map<HighscoreEntry, SongScore> = [];
@:dox(hide) @:doNotSave private static var __eventAdded = false;
@:doNotSave public static var save:FlxSave;
@@ -45,7 +45,8 @@ class FunkinSave {
}
}
private static function __load() {
public static function load() {
__load();
if (save.data.highscores != null) {
var temp;
for (entryData in Reflect.fields(save.data.highscores)) if ((temp = __getHighscoreEntry(entryData)) != null)
@@ -53,7 +54,8 @@ class FunkinSave {
}
}
private static function __flush() {
public static function flush() {
__flush();
if (save.data.highscores == null) save.data.highscores = {};
for (entry => score in highscores) Reflect.setField(save.data.highscores, __formatHighscoreEntry(entry), score);
}
@@ -62,7 +64,7 @@ class FunkinSave {
try {
var d = Unserializer.run(data);
if (d.song is String)
return HSongEntry(d.song, d.diff, d.changes);
return HSongEntry(d.song, d.diff, d.variation, d.changes);
else if (d.week is String)
return HWeekEntry(d.week, d.diff);
}
@@ -72,10 +74,10 @@ class FunkinSave {
static function __formatHighscoreEntry(entry:HighscoreEntry):String {
switch (entry) {
case HWeekEntry(weekName:String, difficulty:String):
case HWeekEntry(weekName, difficulty):
return Serializer.run({week: weekName, diff: difficulty});
case HSongEntry(songName:String, difficulty:String, variation:Null<String>, changes:Array<HighscoreChange>):
var d = {
case HSongEntry(songName, difficulty, variation, changes):
var d:Dynamic = {
song: songName,
diff: difficulty,
changes: changes
@@ -92,14 +94,14 @@ class FunkinSave {
* @param diff Song difficulty
* @param changes Changes made to that song in freeplay.
*/
public static inline function getSongHighscore(name:String, diff:String, ?changes:Array<HighscoreChange>) {
public static inline function getSongHighscore(name:String, diff:String, ?variation:String, ?changes:Array<HighscoreChange>) {
if (changes == null) changes = [];
return safeGetHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), changes));
return safeGetHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), variation, changes));
}
public static inline function setSongHighscore(name:String, diff:String, highscore:SongScore, ?changes:Array<HighscoreChange>) {
public static inline function setSongHighscore(name:String, diff:String, ?variation:String, highscore:SongScore, ?changes:Array<HighscoreChange>) {
if (changes == null) changes = [];
if (safeRegisterHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), changes), highscore)) {
if (safeRegisterHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), variation, changes), highscore)) {
flush();
return true;
}