new chart editor, sm file support, bpm changes, and scroll speed changes.
This commit is contained in:
parent
c69e83d8e0
commit
aa2119d034
@ -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,6 +91,8 @@
|
||||
<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' />
|
||||
|
@ -76,3 +76,4 @@ This game was made with love to Newgrounds and its community. Extra love to Tom
|
||||
- [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
|
||||
- [Poco](https://github.com/poco0317) - math degree (aka most of the fucking math in this project)
|
BIN
assets/preload/images/stepmania-icon.png
Normal file
BIN
assets/preload/images/stepmania-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
1
assets/sm/HOW TO ADD SM FILES.txt
Normal file
1
assets/sm/HOW TO ADD SM FILES.txt
Normal 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
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
/*
|
||||
@ -315,6 +354,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());
|
||||
}
|
||||
}
|
||||
@ -328,6 +379,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) {
|
||||
@ -353,6 +405,7 @@ class FreeplayState extends MusicBeatState
|
||||
FlxG.sound.play(Paths.sound('scrollMenu'), 0.4);
|
||||
|
||||
|
||||
|
||||
curSelected += change;
|
||||
|
||||
if (curSelected < 0)
|
||||
@ -379,7 +432,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;
|
||||
@ -428,12 +491,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
|
||||
}
|
||||
|
@ -13,9 +13,15 @@ class HealthIcon extends FlxSprite
|
||||
{
|
||||
super();
|
||||
|
||||
loadGraphic(Paths.image('iconGrid'), true, 150, 150);
|
||||
|
||||
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);
|
||||
|
@ -12,4 +12,5 @@ class HelperFunctions
|
||||
public static function GCD(a, b) {
|
||||
return b == 0 ? FlxMath.absInt(a) : GCD(b, a % b);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
30
source/OFLWaveform.hx
Normal 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();
|
||||
}
|
||||
}
|
@ -52,6 +52,13 @@ class OutdatedSubState extends MusicBeatState
|
||||
+ "\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;
|
||||
txt.borderSize = 3;
|
||||
@ -84,10 +91,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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
@ -112,6 +118,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;
|
||||
@ -169,6 +181,8 @@ class PlayState extends MusicBeatState
|
||||
|
||||
public static var offsetTesting:Bool = false;
|
||||
|
||||
public var isSMFile:Bool = false;
|
||||
|
||||
var notesHitArray:Array<Date> = [];
|
||||
var currentFrames:Int = 0;
|
||||
|
||||
@ -257,6 +271,8 @@ class PlayState extends MusicBeatState
|
||||
|
||||
override public function create()
|
||||
{
|
||||
|
||||
FlxG.mouse.visible = false;
|
||||
instance = this;
|
||||
|
||||
if (FlxG.save.data.fpsCap > 290)
|
||||
@ -372,6 +388,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);
|
||||
|
||||
@ -1604,7 +1661,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;
|
||||
@ -1689,10 +1759,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');
|
||||
|
||||
@ -1722,6 +1799,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))
|
||||
{
|
||||
var path = haxe.io.Path.join([songPath, file]);
|
||||
@ -2071,12 +2153,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;
|
||||
|
||||
@ -2528,6 +2675,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);
|
||||
|
||||
@ -4164,11 +4314,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);
|
||||
|
||||
|
@ -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
32
source/SectionRender.hx
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
@ -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
55
source/TimingStruct.hx
Normal 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;
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -287,7 +284,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];
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user