Merge branch 'master' into some-options

This commit is contained in:
CyndaquilDAC 2021-07-19 23:22:43 -05:00 committed by GitHub
commit 248f91c94a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 2044 additions and 355 deletions

View File

@ -57,6 +57,7 @@
<library name="week4" preload="true" />
<library name="week5" preload="true" />
<library name="week6" preload="true" />
<library name="sm" preload="true" />
</section>
<section if="NO_PRELOAD_ALL">
@ -69,6 +70,7 @@
<library name="week4" preload="false" />
<library name="week5" preload="false" />
<library name="week6" preload="false" />
<library name="sm" preload="false" />
</section>
<assets path="assets/songs" library="songs" exclude="*.ogg" if="web"/>
@ -89,7 +91,9 @@
<assets path="assets/week5" library="week5" exclude="*.mp3" unless="web"/>
<assets path="assets/week6" library="week6" exclude="*.ogg" if="web"/>
<assets path="assets/week6" library="week6" exclude="*.mp3" unless="web"/>
<assets path="assets/sm" library="sm" exclude="*.ogg" if="web"/>
<assets path="assets/sm" library="sm" exclude="*.mp3" unless="web"/>
<assets path='example_mods' rename='mods' embed='false'/>
<assets path='art/readme.txt' rename='do NOT readme.txt' />
<assets path='LICENSE' rename='LICENSE.txt' />

View File

@ -75,4 +75,5 @@ This game was made with love to Newgrounds and its community. Extra love to Tom
- [GWebDev](https://github.com/GrowtopiaFli) - Video Code
- [Rozebud](https://github.com/ThatRozebudDude) - Ideas (that I stole)
- [Puyo](https://github.com/daniel11420) - Setting up appveyor and a lot of other help
- [Smokey](https://twitter.com/Smokey_5_) - telling me that I should do the tricky asset loading
- [Smokey](https://twitter.com/Smokey_5_) - telling me that I should do the tricky asset loading
- [Poco](https://github.com/poco0317) - math degree (aka most of the fucking math in this project)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -0,0 +1 @@
Put both the .sm and .ogg in the same folder and put the folder in this folder. Launch the game and go into freeplay, it'll load into the song list.

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,6 @@ class Conductor
public static var safeZoneOffset:Float = Math.floor((safeFrames / 60) * 1000); // is calculated in create(), is safeFrames in milliseconds
public static var timeScale:Float = Conductor.safeZoneOffset / 166;
public static var lengthInSteps:Float = 0;
public static var bpmChangeMap:Array<BPMChangeEvent> = [];
public function new()
@ -70,15 +68,27 @@ class Conductor
trace("new BPM map BUDDY " + bpmChangeMap);
}
public static function changeBPM(newBpm:Float)
public static function recalculateTimingStruct(SONG:Song)
{
for(i in SONG.eventObjects)
{
/*TimingStruct.addTiming(beat,bpm,endBeat, Std.parseFloat(OFFSET));
if (changeEvents.length != 0)
{
var data = TimingStruct.AllTimings[currentIndex - 1];
data.endBeat = beat;
data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
TimingStruct.AllTimings[currentIndex].startTime = data.startTime + data.length;
}*/
}
}
public static function changeBPM(newBpm:Float, ?recalcLength = true)
{
bpm = newBpm;
crochet = ((60 / bpm) * 1000);
stepCrochet = crochet / 4;
lengthInSteps = (FlxG.sound.music.length / stepCrochet);
trace("\nLength in in steps: " + lengthInSteps);
}
}

View File

@ -1,5 +1,12 @@
package;
import openfl.utils.Future;
import openfl.media.Sound;
import flixel.system.FlxSound;
#if sys
import smTools.SMFile;
import sys.FileSystem;
import sys.io.File;
#end
import Song.SwagSong;
import flixel.input.gamepad.FlxGamepad;
import flash.text.TextField;
@ -63,6 +70,9 @@ class FreeplayState extends MusicBeatState
//var diffList = "";
songData = [];
songs = [];
for (i in 0...initSonglist.length)
{
var data:Array<String> = initSonglist[i].split(':');
@ -83,6 +93,35 @@ class FreeplayState extends MusicBeatState
}
trace("tryin to load sm files");
#if sys
for(i in FileSystem.readDirectory("assets/sm/"))
{
trace(i);
if (FileSystem.isDirectory("assets/sm/" + i))
{
trace("Reading SM file dir " + i);
for (file in FileSystem.readDirectory("assets/sm/" + i))
{
if (file.contains(" "))
FileSystem.rename("assets/sm/" + i + "/" + file,"assets/sm/" + i + "/" + file.replace(" ","_"));
if (file.endsWith(".sm"))
{
trace("reading " + file);
var file:SMFile = SMFile.loadFile("assets/sm/" + i + "/" + file.replace(" ","_"));
trace("Converting " + file.header.TITLE);
var data = file.convertToFNF("assets/sm/" + i + "/converted.json");
var meta = new SongMetadata(file.header.TITLE, 0, "sm",file,"assets/sm/" + i);
songs.push(meta);
var song = Song.loadFromJsonRAW(data);
songData.set(file.header.TITLE, [song,song,song]);
}
}
}
}
#end
//trace("\n" + diffList);
/*
@ -319,6 +358,18 @@ class FreeplayState extends MusicBeatState
PlayState.storyDifficulty = curDifficulty;
PlayState.storyWeek = songs[curSelected].week;
trace('CUR WEEK' + PlayState.storyWeek);
#if sys
if (songs[curSelected].songCharacter == "sm")
{
PlayState.isSM = true;
PlayState.sm = songs[curSelected].sm;
PlayState.pathToSm = songs[curSelected].path;
}
else
PlayState.isSM = false;
#else
PlayState.isSM = false;
#end
LoadingState.loadAndSwitchState(new PlayState());
}
}
@ -332,6 +383,7 @@ class FreeplayState extends MusicBeatState
if (curDifficulty > 2)
curDifficulty = 0;
// adjusting the highscore song name to be compatible (changeDiff)
var songHighscore = StringTools.replace(songs[curSelected].songName, " ", "-");
switch (songHighscore) {
@ -357,6 +409,7 @@ class FreeplayState extends MusicBeatState
FlxG.sound.play(Paths.sound('scrollMenu'), 0.4);
curSelected += change;
if (curSelected < 0)
@ -383,7 +436,17 @@ class FreeplayState extends MusicBeatState
diffCalcText.text = 'RATING: ${DiffCalc.CalculateDiff(songData.get(songs[curSelected].songName)[curDifficulty])}';
#if PRELOAD_ALL
FlxG.sound.playMusic(Paths.inst(songs[curSelected].songName), 0);
if (songs[curSelected].songCharacter == "sm")
{
var data = songs[curSelected];
trace("Loading " + data.path + "/" + data.sm.header.MUSIC);
var bytes = File.getBytes(data.path + "/" + data.sm.header.MUSIC);
var sound = new Sound();
sound.loadCompressedDataFromByteArray(bytes.getData(), bytes.length);
FlxG.sound.playMusic(sound);
}
else
FlxG.sound.playMusic(Paths.inst(songs[curSelected].songName), 0);
#end
var hmm;
@ -432,12 +495,27 @@ class SongMetadata
{
public var songName:String = "";
public var week:Int = 0;
#if sys
public var sm:SMFile;
public var path:String;
#end
public var songCharacter:String = "";
#if sys
public function new(song:String, week:Int, songCharacter:String, ?sm:SMFile = null, ?path:String = "")
{
this.songName = song;
this.week = week;
this.songCharacter = songCharacter;
this.sm = sm;
this.path = path;
}
#else
public function new(song:String, week:Int, songCharacter:String)
{
this.songName = song;
this.week = week;
this.songCharacter = songCharacter;
}
#end
}

View File

@ -12,13 +12,17 @@ class HealthIcon extends FlxSprite
public function new(char:String = 'bf', isPlayer:Bool = false)
{
super();
loadGraphic(Paths.image('iconGrid'), true, 150, 150);
if(FlxG.save.data.antialiasing)
{
antialiasing = true;
}
if (char == 'sm')
{
loadGraphic(Paths.image("stepmania-icon"));
return;
}
loadGraphic(Paths.image('iconGrid'), true, 150, 150);
animation.add('bf', [0, 1], 0, false, isPlayer);
animation.add('bf-car', [0, 1], 0, false, isPlayer);
animation.add('bf-christmas', [0, 1], 0, false, isPlayer);

View File

@ -12,4 +12,5 @@ class HelperFunctions
public static function GCD(a, b) {
return b == 0 ? FlxMath.absInt(a) : GCD(b, a % b);
}
}

View File

@ -38,9 +38,9 @@ class MainMenuState extends MusicBeatState
var newGaming2:FlxText;
public static var firstStart:Bool = true;
public static var nightly:String = "";
public static var nightly:String = "-Pre-Release";
public static var kadeEngineVer:String = "1.5.4" + nightly;
public static var kadeEngineVer:String = "1.6" + nightly;
public static var gameVer:String = "0.2.7.1";
var magenta:FlxSprite;

View File

@ -3,15 +3,11 @@ package;
#if windows
import Discord.DiscordClient;
#end
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import openfl.Lib;
import Conductor.BPMChangeEvent;
import flixel.FlxG;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.ui.FlxUIState;
import flixel.math.FlxRect;
import flixel.util.FlxTimer;
class MusicBeatState extends FlxUIState
{
@ -20,6 +16,7 @@ class MusicBeatState extends FlxUIState
private var curStep:Int = 0;
private var curBeat:Int = 0;
private var curDecimalBeat:Float = 0;
private var controls(get, never):Controls;
inline function get_controls():Controls
@ -27,6 +24,7 @@ class MusicBeatState extends FlxUIState
override function create()
{
TimingStruct.clearTimings();
(cast (Lib.current.getChildAt(0), Main)).setFPSCap(FlxG.save.data.fpsCap);
if (transIn != null)
@ -73,6 +71,29 @@ class MusicBeatState extends FlxUIState
}
}
if (Conductor.songPosition < 0)
curDecimalBeat = 0;
else
{
if (TimingStruct.AllTimings.length > 1)
{
var data = TimingStruct.getTimingAtTimestamp(Conductor.songPosition);
FlxG.watch.addQuick("Current Conductor Timing Seg", data.bpm);
Conductor.crochet = ((60 / data.bpm) * 1000);
var percent = (Conductor.songPosition - (data.startTime * 1000)) / (data.length * 1000);
curDecimalBeat = data.startBeat + (((Conductor.songPosition/1000) - data.startTime) * (data.bpm / 60));
}
else
{
curDecimalBeat = (Conductor.songPosition / 1000) * (Conductor.bpm/60);
Conductor.crochet = ((60 / Conductor.bpm) * 1000);
}
}
if (FlxG.save.data.fpsRain && skippedFrames >= 6)
{
if (currentColor >= array.length)

View File

@ -33,6 +33,8 @@ class Note extends FlxSprite
public var originColor:Int = 0; // The sustain note's original note's color
public var noteSection:Int = 0;
public var noteCharterObject:FlxSprite;
public var noteScore:Float = 1;
public var noteYOff:Int = 0;

30
source/OFLWaveform.hx Normal file
View File

@ -0,0 +1,30 @@
import lime.media.AudioSource;
import lime.media.AudioBuffer;
import openfl.media.Sound;
import openfl.display.Graphics;
import openfl.display.Sprite;
class OFLWaveform extends Sprite
{
public var musicLength = 0;
public var _x = 0;
public var _y = 0;
public var _sound:String;
function new(x,y,musicLength, data:String)
{
super();
_x = x;
_y = y;
_sound = data;
this.musicLength = musicLength;
}
public function drawWaveform()
{
var gfx:Graphics = graphics;
gfx.clear();
}
}

View File

@ -59,6 +59,13 @@ class OutdatedSubState extends MusicBeatState
+ "\n& more changes and bugfixes in the full changelog"
+ "\n\nPress Space to view the full changelog and update\nor ESCAPE to ignore this",
32);
if (MainMenuState.nightly != "")
txt.text =
"You are on\n"
+ MainMenuState.kadeEngineVer + "-" + MainMenuState.nightly
+ "\nWhich is a PRE-RELEASE BUILD!"
+ "\n\nReport all bugs to the author of the pre-release.\nSpace/Escape ignores this.";
txt.setFormat("VCR OSD Mono", 32, FlxColor.fromRGB(200, 200, 200), CENTER);
txt.borderColor = FlxColor.BLACK;
@ -92,10 +99,15 @@ class OutdatedSubState extends MusicBeatState
override function update(elapsed:Float)
{
if (controls.ACCEPT)
if (controls.ACCEPT && MainMenuState.nightly == "")
{
fancyOpenURL("https://kadedev.github.io/Kade-Engine/changelogs/changelog-" + needVer);
}
else if (controls.ACCEPT)
{
leftState = true;
FlxG.switchState(new MainMenuState());
}
if (controls.BACK)
{
leftState = true;

View File

@ -133,6 +133,11 @@ class PauseSubState extends MusicBeatSubstate
}
var songPath = 'assets/data/' + songLowercase + '/';
#if sys
if (PlayState.isSM && !PlayState.isStoryMode)
songPath = PlayState.pathToSm;
#end
if (controls.UP_P || upPcontroller)
{
changeSelection(-1);

View File

@ -1,5 +1,11 @@
package;
import Song.Event;
import openfl.media.Sound;
#if sys
import sys.io.File;
import smTools.SMFile;
#end
import openfl.ui.KeyLocation;
import openfl.events.Event;
import haxe.EnumTools;
@ -113,6 +119,12 @@ class PlayState extends MusicBeatState
private var vocals:FlxSound;
public static var isSM:Bool = false;
#if sys
public static var sm:SMFile;
public static var pathToSm:String;
#end
public var originalX:Float;
public static var dad:Character;
@ -170,6 +182,8 @@ class PlayState extends MusicBeatState
public static var offsetTesting:Bool = false;
public var isSMFile:Bool = false;
var notesHitArray:Array<Date> = [];
var currentFrames:Int = 0;
var idleToBeat:Bool = true; // change if bf and dad would idle to the beat of the song
@ -261,6 +275,8 @@ class PlayState extends MusicBeatState
override public function create()
{
FlxG.mouse.visible = false;
instance = this;
if (FlxG.save.data.fpsCap > 290)
@ -377,6 +393,47 @@ class PlayState extends MusicBeatState
Conductor.mapBPMChanges(SONG);
Conductor.changeBPM(SONG.bpm);
if (SONG.eventObjects == null)
{
SONG.eventObjects = [new Song.Event("Init BPM",0,SONG.bpm,"BPM Change")];
}
TimingStruct.clearTimings();
var convertedStuff:Array<Song.Event> = [];
var currentIndex = 0;
for (i in SONG.eventObjects)
{
var name = Reflect.field(i,"name");
var type = Reflect.field(i,"type");
var pos = Reflect.field(i,"position");
var value = Reflect.field(i,"value");
if (type == "BPM Change")
{
var beat:Float = pos;
var endBeat:Float = Math.POSITIVE_INFINITY;
TimingStruct.addTiming(beat,value,endBeat, 0); // offset in this case = start time since we don't have a offset
if (currentIndex != 0)
{
var data = TimingStruct.AllTimings[currentIndex - 1];
data.endBeat = beat;
data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
TimingStruct.AllTimings[currentIndex].startTime = data.startTime + data.length;
}
currentIndex++;
}
convertedStuff.push(new Song.Event(name,pos,value,type));
}
SONG.eventObjects = convertedStuff;
trace('INFORMATION ABOUT WHAT U PLAYIN WIT:\nFRAMES: ' + PlayStateChangeables.safeFrames + '\nZONE: ' + Conductor.safeZoneOffset + '\nTS: '
+ Conductor.timeScale + '\nBotPlay : ' + PlayStateChangeables.botPlay);
@ -1630,7 +1687,20 @@ class PlayState extends MusicBeatState
if (!paused)
{
#if sys
if (!isStoryMode && isSM)
{
trace("Loading " + pathToSm + "/" + sm.header.MUSIC);
var bytes = File.getBytes(pathToSm + "/" + sm.header.MUSIC);
var sound = new Sound();
sound.loadCompressedDataFromByteArray(bytes.getData(), bytes.length);
FlxG.sound.playMusic(sound);
}
else
FlxG.sound.playMusic(Paths.inst(PlayState.SONG.song), 1, false);
#else
FlxG.sound.playMusic(Paths.inst(PlayState.SONG.song), 1, false);
#end
}
FlxG.sound.music.onComplete = endSong;
@ -1715,10 +1785,17 @@ class PlayState extends MusicBeatState
curSong = songData.song;
#if sys
if (SONG.needsVoices && !isSM)
vocals = new FlxSound().loadEmbedded(Paths.voices(PlayState.SONG.song));
else
vocals = new FlxSound();
#else
if (SONG.needsVoices)
vocals = new FlxSound().loadEmbedded(Paths.voices(PlayState.SONG.song));
else
vocals = new FlxSound();
#end
trace('loaded vocals');
@ -1747,6 +1824,11 @@ class PlayState extends MusicBeatState
}
var songPath = 'assets/data/' + songLowercase + '/';
#if sys
if (isSM && !isStoryMode)
songPath = pathToSm;
#end
for (file in sys.FileSystem.readDirectory(songPath))
{
@ -2100,12 +2182,77 @@ class PlayState extends MusicBeatState
public var stopUpdate = false;
public var removedVideo = false;
public var currentBPM = 0;
public var updateFrame = 0;
override public function update(elapsed:Float)
{
#if !debug
perfectMode = false;
#end
if (updateFrame == 4)
{
TimingStruct.clearTimings();
var currentIndex = 0;
for (i in SONG.eventObjects)
{
if (i.type == "BPM Change")
{
var beat:Float = i.position;
var endBeat:Float = Math.POSITIVE_INFINITY;
TimingStruct.addTiming(beat,i.value,endBeat, 0); // offset in this case = start time since we don't have a offset
if (currentIndex != 0)
{
var data = TimingStruct.AllTimings[currentIndex - 1];
data.endBeat = beat;
data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
TimingStruct.AllTimings[currentIndex].startTime = data.startTime + data.length;
}
currentIndex++;
}
}
updateFrame++;
}
else if (updateFrame != 5)
updateFrame++;
var timingSeg = TimingStruct.getTimingAtTimestamp(Conductor.songPosition);
if (timingSeg != null)
{
var timingSegBpm = timingSeg.bpm;
if (timingSegBpm != Conductor.bpm)
{
trace("BPM CHANGE to " + timingSegBpm);
Conductor.changeBPM(timingSegBpm, false);
}
}
var newScroll = PlayStateChangeables.scrollSpeed;
for(i in SONG.eventObjects)
{
switch(i.type)
{
case "Scroll Speed Change":
if (i.position < curDecimalBeat)
newScroll = i.value;
}
}
PlayStateChangeables.scrollSpeed = newScroll;
if (PlayStateChangeables.botPlay && FlxG.keys.justPressed.ONE)
camHUD.visible = !camHUD.visible;
@ -2596,6 +2743,9 @@ class PlayState extends MusicBeatState
camHUD.zoom = FlxMath.lerp(1, camHUD.zoom, 0.95);
}
FlxG.watch.addQuick("curBPM", Conductor.bpm);
FlxG.watch.addQuick("Closest Note", (unspawnNotes.length != 0 ? unspawnNotes[0].strumTime - Conductor.songPosition : "No note"));
FlxG.watch.addQuick("beatShit", curBeat);
FlxG.watch.addQuick("stepShit", curStep);
@ -4259,11 +4409,6 @@ class PlayState extends MusicBeatState
if (SONG.notes[Math.floor(curStep / 16)] != null)
{
if (SONG.notes[Math.floor(curStep / 16)].changeBPM)
{
Conductor.changeBPM(SONG.notes[Math.floor(curStep / 16)].bpm);
FlxG.log.add('CHANGED BPM!');
}
// else
// Conductor.changeBPM(SONG.bpm);

View File

@ -2,6 +2,8 @@ package;
typedef SwagSection =
{
var startTime:Float;
var endTime:Float;
var sectionNotes:Array<Array<Dynamic>>;
var lengthInSteps:Int;
var typeOfSection:Int;
@ -13,6 +15,8 @@ typedef SwagSection =
class Section
{
public var startTime:Float = 0;
public var endTime:Float = 0;
public var sectionNotes:Array<Array<Dynamic>> = [];
public var lengthInSteps:Int = 16;

32
source/SectionRender.hx Normal file
View File

@ -0,0 +1,32 @@
import flixel.FlxG;
import flixel.util.FlxColor;
import flixel.group.FlxGroup.FlxTypedGroup;
import Section.SwagSection;
import flixel.addons.display.FlxGridOverlay;
import flixel.FlxSprite;
class SectionRender extends FlxSprite
{
public var section:SwagSection;
public var icon:FlxSprite;
public var lastUpdated:Bool;
public function new(x:Float,y:Float,GRID_SIZE:Int, ?Height:Int = 16)
{
super(x,y);
makeGraphic(GRID_SIZE * 8, GRID_SIZE * Height,FlxColor.BLACK);
var h = GRID_SIZE;
if (Math.floor(h) != h)
h = GRID_SIZE;
FlxGridOverlay.overlay(this,GRID_SIZE, Std.int(h), GRID_SIZE * 8,GRID_SIZE * Height);
}
override function update(elapsed)
{
}
}

View File

@ -7,10 +7,28 @@ import lime.utils.Assets;
using StringTools;
class Event
{
public var name:String;
public var position:Float;
public var value:Dynamic;
public var type:String;
public function new(name:String,pos:Float,value:Dynamic,type:String)
{
this.name = name;
this.position = pos;
this.value = value;
this.type = type;
}
}
typedef SwagSong =
{
var chartVersion:String;
var song:String;
var notes:Array<SwagSection>;
var eventObjects:Array<Event>;
var bpm:Float;
var needsVoices:Bool;
var speed:Float;
@ -25,10 +43,12 @@ typedef SwagSong =
class Song
{
public var chartVersion:String;
public var song:String;
public var notes:Array<SwagSection>;
public var bpm:Float;
public var needsVoices:Bool = true;
public var eventObjects:Array<Event>;
public var speed:Float = 1;
public var player1:String = 'bf';
@ -44,10 +64,19 @@ class Song
this.bpm = bpm;
}
public static function loadFromJsonRAW(rawJson:String)
{
while (!rawJson.endsWith("}"))
{
rawJson = rawJson.substr(0, rawJson.length - 1);
// LOL GOING THROUGH THE BULLSHIT TO CLEAN IDK WHATS STRANGE
}
return parseJSONshit(rawJson);
}
public static function loadFromJson(jsonInput:String, ?folder:String):SwagSong
{
trace(jsonInput);
// pre lowercasing the folder name
var folderLowercase = StringTools.replace(folder, " ", "-").toLowerCase();
switch (folderLowercase) {

55
source/TimingStruct.hx Normal file
View File

@ -0,0 +1,55 @@
import flixel.FlxG;
class TimingStruct
{
public static var AllTimings:Array<TimingStruct> = [];
public var bpm:Float = 0;
public var startBeat:Float = 0;
public var endBeat:Float = Math.POSITIVE_INFINITY;
public var startTime:Float = 0;
public var length:Float = Math.POSITIVE_INFINITY; // in beats
public static function clearTimings()
{
AllTimings = [];
}
public static function addTiming(startBeat,bpm,endBeat:Float, offset:Float)
{
var pog = new TimingStruct(startBeat,bpm,endBeat, offset);
AllTimings.push(pog);
}
public function new(startBeat,bpm,endBeat:Float, offset:Float)
{
this.bpm = bpm;
this.startBeat = startBeat;
if (endBeat != -1)
this.endBeat = endBeat;
startTime = offset;
}
public static function getTimingAtTimestamp(msTime:Float):TimingStruct
{
for(i in AllTimings)
{
if (msTime >= i.startTime * 1000 && msTime < (i.startTime + i.length) * 1000)
return i;
}
trace('Apparently ' + msTime + ' is out of any segs');
return null;
}
public static function getTimingAtBeat(beat):TimingStruct
{
for(i in AllTimings)
{
if (i.startBeat <= beat && i.endBeat >= beat)
return i;
}
return null;
}
}

View File

@ -84,9 +84,6 @@ class TitleState extends MusicBeatState
trace('NEWGROUNDS LOL');
#end
// var file:SMFile = SMFile.loadFile("file.sm");
// this was testing things
#if FREEPLAY
FlxG.switchState(new FreeplayState());
#elseif CHARTING
@ -303,7 +300,7 @@ class TitleState extends MusicBeatState
{
returnedData[0] = data.substring(0, data.indexOf(';'));
returnedData[1] = data.substring(data.indexOf('-'), data.length);
if (!MainMenuState.kadeEngineVer.contains(returnedData[0].trim()) && !OutdatedSubState.leftState && MainMenuState.nightly == "")
if (!MainMenuState.kadeEngineVer.contains(returnedData[0].trim()) && !OutdatedSubState.leftState)
{
trace('outdated lmao! ' + returnedData[0] + ' != ' + MainMenuState.kadeEngineVer);
OutdatedSubState.needVer = returnedData[0];

View File

@ -1,7 +1,9 @@
#if sys
package smTools;
import sys.io.File;
import haxe.Exception;
import lime.app.Application;
import haxe.Json;
class SMFile
{
@ -12,6 +14,10 @@ class SMFile
private var _fileData:Array<String>;
public var isDouble:Bool = false;
public var isValid:Bool = true;
public var _readTime:Float = 0;
public var header:SMHeader;
@ -19,43 +25,230 @@ class SMFile
public function new(data:Array<String>)
{
_fileData = data;
// Gather header data
var headerData = "";
var inc = 0;
while(!StringTools.contains(data[inc + 1],"//"))
try
{
headerData += data[inc] + "\n";
inc++;
// trace(data[inc]);
}
_fileData = data;
header = new SMHeader(headerData.split('\n'));
// check if this is a valid file, it should be a dance double file.
inc += 3; // skip three lines down
if (!StringTools.contains(data[inc],"dance-double:"))
return;
trace('this is dance double');
inc += 4; // skip 5 down to where da notes @
trace(data[inc]);
measures = [];
while(data[inc + 1] != ";")
{
var measure = "";
while(data[inc + 1] != ",")
// Gather header data
var headerData = "";
var inc = 0;
while(!StringTools.contains(data[inc + 1],"//"))
{
headerData += data[inc];
inc++;
var line = data[inc];
measure += line + "\n";
// trace(data[inc]);
}
measures.push(new SMMeasure(measure.split('\n')));
header = new SMHeader(headerData.split(';'));
if (!StringTools.contains(header.MUSIC,"ogg"))
{
Application.current.window.alert("The music MUST be an OGG File.","SM File loading (" + header.TITLE + ")");
isValid = false;
return;
}
// check if this is a valid file, it should be a dance double file.
inc += 3; // skip three lines down
if (!StringTools.contains(data[inc],"dance-double:") && !StringTools.contains(data[inc],"dance-single"))
{
Application.current.window.alert("The file you are loading is neither a Dance Double chart or a Dance Single chart","SM File loading (" + header.TITLE + ")");
isValid = false;
return;
}
if (StringTools.contains(data[inc],"dance-double:"))
isDouble = true;
if (isDouble)
trace('this is dance double');
inc += 5; // skip 5 down to where da notes @
measures = [];
var measure = "";
trace(data[inc - 1]);
for (ii in inc...data.length)
{
var i = data[ii];
if (StringTools.contains(i,",") || StringTools.contains(i,";"))
{
measures.push(new SMMeasure(measure.split('\n')));
//trace(measures.length);
measure = "";
continue;
}
measure += i + "\n";
}
trace(measures.length + " Measures");
}
trace(measures.length + " Measures");
catch(e:Exception)
{
Application.current.window.alert("Failure to load file.\n" + e,"SM File loading");
}
}
public function convertToFNF(saveTo:String):String
{
// array's for helds
var heldNotes:Array<Array<Dynamic>>;
if (isDouble) // held storage lanes
heldNotes = [[],[],[],[],[],[],[],[]];
else
heldNotes = [[],[],[],[]];
// variables
var measureIndex = 0;
var currentBeat:Float = 0;
var output = "";
// init a fnf song
var song = {
song: header.TITLE,
notes: [],
eventObjects: [],
bpm: header.getBPM(0),
needsVoices: true,
player1: 'bf',
player2: 'gf',
gfVersion: 'gf',
noteStyle: 'normal',
stage: 'stage',
speed: 1.0,
validScore: false
};
// lets check if the sm loading was valid
if (!isValid)
{
var json = {
"song": song
};
var data:String = Json.stringify(json,null," ");
File.saveContent(saveTo,data);
return data;
}
// aight time to convert da measures
trace("Converting measures");
for(measure in measures)
{
// private access since _measure is private
@:privateAccess
var lengthInRows = 192 / (measure._measure.length - 1);
var rowIndex = 0;
// section declaration
var section = {
sectionNotes: [],
lengthInSteps: 16,
typeOfSection: 0,
mustHitSection: false,
bpm: header.getBPM(0),
changeBPM: false,
altAnim: false
};
// if it's not a double always set this to true
if (!isDouble)
section.mustHitSection = true;
@:privateAccess
for(i in 0...measure._measure.length - 1)
{
var noteRow = (measureIndex * 192) + (lengthInRows * rowIndex);
var notes:Array<String> = [];
for(note in measure._measure[i].split(''))
{
//output += note;
notes.push(note);
}
currentBeat = noteRow / 48;
var seg = TimingStruct.getTimingAtBeat(currentBeat);
var timeInSec:Float = (seg.startTime + ((currentBeat - seg.startBeat) / (seg.bpm/60)));
var rowTime = timeInSec * 1000;
//output += " - Row " + noteRow + " - Time: " + rowTime + " (" + timeInSec + ") - Beat: " + currentBeat + " - Current BPM: " + header.getBPM(currentBeat) + "\n";
var index = 0;
var takeover = false;
for(i in notes)
{
// if its a mine lets skip (maybe add mines in the future??)
if (i == "M")
continue;
// get the lane and note type
var lane = index;
var numba = Std.parseInt(i);
// switch through the type and add the note
switch(numba)
{
case 1: // normal
section.sectionNotes.push([rowTime,lane ,0]);
case 2: // held head
heldNotes[lane] = [rowTime,lane,0];
case 3: // held tail
var data = heldNotes[lane];
var timeDiff = rowTime - data[0];
section.sectionNotes.push([data[0],lane,timeDiff]);
heldNotes[index] = [];
}
index++;
}
rowIndex++;
}
// push the section
song.notes.push(section);
//output += ",\n";
measureIndex++;
}
//File.saveContent("fuac" + header.TITLE,output);
if (header.changeEvents.length != 0)
{
song.eventObjects = header.changeEvents;
}
// save da song
var json = {
"song": song
};
var data:String = Json.stringify(json,null," ");
File.saveContent(saveTo,data);
return data;
}
}
#end

View File

@ -15,13 +15,83 @@ class SMHeader
public var BACKGROUND = "";
public var CDTITLE = "";
public var OFFSET = "";
public var BPMS = "";
public var BPMS = ""; // time=bpm
public var changeEvents:Array<Song.Event>;
public function new(headerData:Array<String>)
{
_header = headerData;
for (i in headerData)
{
readHeaderLine(i);
}
trace(BPMS);
MUSIC = StringTools.replace(MUSIC," ", "_");
changeEvents = [];
getBPM(0,true);
}
public function getBeatFromBPMIndex(index):Float
{
var bpmSplit = BPMS.split(',');
var beat = 0;
for(ii in 0...bpmSplit.length)
{
if (ii == index)
return Std.parseFloat(StringTools.replace(bpmSplit[ii].split('=')[0],",",""));
}
return 0.0;
}
public function getBPM(beat:Float, printAllBpms:Bool = false)
{
var bpmSplit = BPMS.split(',');
if (printAllBpms)
{
TimingStruct.clearTimings();
var currentIndex = 0;
for(i in bpmSplit)
{
var bpm:Float = Std.parseFloat(i.split('=')[1]);
var beat:Float = Std.parseFloat(StringTools.replace(i.split('=')[0],",",""));
var endBeat:Float = Math.POSITIVE_INFINITY;
TimingStruct.addTiming(beat,bpm,endBeat, -Std.parseFloat(OFFSET));
if (changeEvents.length != 0)
{
var data = TimingStruct.AllTimings[currentIndex - 1];
data.endBeat = beat;
data.length = (data.endBeat - data.startBeat) / (data.bpm / 60);
TimingStruct.AllTimings[currentIndex].startTime = data.startTime + data.length;
}
changeEvents.push(new Song.Event(HelperFunctions.truncateFloat(beat,0) + "SM",beat,bpm,"BPM Change"));
if (bpmSplit.length == 1)
break;
currentIndex++;
}
trace(changeEvents.length + " - BPM CHANGES");
return 0.0;
}
var returningBPM = Std.parseFloat(bpmSplit[0].split('=')[1]);
for(i in bpmSplit)
{
var bpm:Float = Std.parseFloat(i.split('=')[1]);
var beatt:Float = Std.parseFloat(StringTools.replace(i.split('=')[0],",",""));
if (beatt <= beat)
returningBPM = bpm;
}
return returningBPM;
}
function readHeaderLine(line:String)

View File

@ -11,6 +11,19 @@ class SMMeasure
{
_measure = measureData;
notes = [];
// 0 = no note
// 1 = normal note
// 2 = head of sustain
// 3 = tail of sustain
for(i in measureData)
{
for (ii in 0...i.length)
{
notes.push(new SMNote(i.split('')[ii],ii));
}
}
}
}
#end

View File

@ -3,8 +3,13 @@ package smTools;
class SMNote
{
public var time:Float;
public var data:Int;
public var length:Float;
public var data:String;
public var lane:Int;
public function new(_data:String,_lane:Int)
{
data = _data;
lane = _lane;
}
}
#end