Tobee_Night_Funkin_PSYCH/source/editors/ChartingState.hx

2195 lines
64 KiB
Haxe

package editors;
#if desktop
import Discord.DiscordClient;
#end
import Conductor.BPMChangeEvent;
import Section.SwagSection;
import Song.SwagSong;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxObject;
import flixel.input.keyboard.FlxKey;
import flixel.addons.display.FlxGridOverlay;
import flixel.addons.ui.FlxInputText;
import flixel.addons.ui.FlxUI9SliceSprite;
import flixel.addons.ui.FlxUI;
import flixel.addons.ui.FlxUICheckBox;
import flixel.addons.ui.FlxUIInputText;
import flixel.addons.ui.FlxUINumericStepper;
import flixel.addons.ui.FlxUITabMenu;
import flixel.addons.ui.FlxUITooltip.FlxUITooltipStyle;
import flixel.addons.transition.FlxTransitionableState;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.group.FlxGroup;
import flixel.math.FlxMath;
import flixel.math.FlxPoint;
import flixel.system.FlxSound;
import flixel.text.FlxText;
import flixel.ui.FlxButton;
import flixel.ui.FlxSpriteButton;
import flixel.util.FlxColor;
import haxe.Json;
import haxe.format.JsonParser;
import lime.utils.Assets;
import openfl.events.Event;
import openfl.events.IOErrorEvent;
import openfl.media.Sound;
import openfl.net.FileReference;
import openfl.utils.ByteArray;
import openfl.utils.Assets as OpenFlAssets;
import lime.media.AudioBuffer;
import haxe.io.Bytes;
import flash.geom.Rectangle;
#if MODS_ALLOWED
import sys.io.File;
import sys.FileSystem;
import flash.media.Sound;
#end
using StringTools;
class ChartingState extends MusicBeatState
{
public static var noteTypeList:Array<String> = //Used for backwards compatibility with 0.1 - 0.3.2 charts, though, you should add your hardcoded custom note types here too.
[
'',
'Alt Animation',
'Hey!',
'Hurt Note',
'GF Sing',
'No Animation'
];
private var noteTypeIntMap:Map<Int, String> = new Map<Int, String>();
private var noteTypeMap:Map<String, Null<Int>> = new Map<String, Null<Int>>();
var eventStuff:Array<Dynamic> =
[
['', "Nothing. Yep, that's right."],
['Hey!', "Plays the \"Hey!\" animation from Bopeebo,\nValue 1: BF = Only Boyfriend, GF = Only Girlfriend,\nSomething else = Both.\nValue 2: Custom animation duration,\nleave it blank for 0.6s"],
['Set GF Speed', "Sets GF head bopping speed,\nValue 1: 1 = Normal speed,\n2 = 1/2 speed, 4 = 1/4 speed etc.\nUsed on Fresh during the beatbox parts.\n\nWarning: Value must be integer!"],
['Blammed Lights', "Value 1: 0 = Turn off, 1 = Blue, 2 = Green,\n3 = Pink, 4 = Red, 5 = Orange, Anything else = Random."],
['Kill Henchmen', "For Mom's songs, don't use this please, i love them :("],
['Add Camera Zoom', "Used on MILF on that one \"hard\" part\nValue 1: Camera zoom add (Default: 0.015)\nValue 2: UI zoom add (Default: 0.03)\nLeave the values blank if you want to use Default."],
['BG Freaks Expression', "Should be used only in \"school\" Stage!"],
['Trigger BG Ghouls', "Should be used only in \"schoolEvil\" Stage!"],
['Play Animation', "Plays an animation on a Character,\nonce the animation is completed,\nthe animation changes to Idle\n\nValue 1: Animation to play.\nValue 2: Character (Dad, BF, GF)"],
['Camera Follow Pos', "Value 1: X\nValue 2: Y\n\nThe camera won't change the follow point\nafter using this, for getting it back\nto normal, leave both values blank."],
['Alt Idle Animation', "Sets a speciied suffix after the idle animation name.\nYou can use this to trigger 'idle-alt' if you set\nValue 2 to -alt\n\nValue 1: Character to set (Dad, BF or GF)\nValue 2: New suffix (Leave it blank to disable)"],
['Screen Shake', "Value 1: Camera shake\nValue 2: HUD shake\n\nEvery value works as the following example: \"1, 0.05\".\nThe first number (1) is the duration.\nThe second number (0.05) is the intensity."],
['Change Character', "Value 1: Character to change (Dad, BF, GF)\nValue 2: New character's name"]
];
var _file:FileReference;
var UI_box:FlxUITabMenu;
/**
* Array of notes showing when each section STARTS in STEPS
* Usually rounded up??
*/
public static var curSection:Int = 0;
public static var lastSection:Int = 0;
private static var lastSong:String = '';
var bpmTxt:FlxText;
var camPos:FlxObject;
var strumLine:FlxSprite;
var curSong:String = 'Dadbattle';
var amountSteps:Int = 0;
var bullshitUI:FlxGroup;
var highlight:FlxSprite;
public static var GRID_SIZE:Int = 40;
var CAM_OFFSET:Int = 360;
var dummyArrow:FlxSprite;
var curRenderedSustains:FlxTypedGroup<FlxSprite>;
var curRenderedNotes:FlxTypedGroup<Note>;
var curRenderedNoteType:FlxTypedGroup<FlxText>;
var nextRenderedSustains:FlxTypedGroup<FlxSprite>;
var nextRenderedNotes:FlxTypedGroup<Note>;
var gridBG:FlxSprite;
var gridMult:Int = 2;
var _song:SwagSong;
/*
* WILL BE THE CURRENT / LAST PLACED NOTE
**/
var curSelectedNote:Array<Dynamic> = null;
var tempBpm:Float = 0;
var vocals:FlxSound = null;
var leftIcon:HealthIcon;
var rightIcon:HealthIcon;
var value1InputText:FlxUIInputText;
var value2InputText:FlxUIInputText;
var currentSongName:String;
var zoomTxt:FlxText;
var curZoom:Int = 1;
#if !html5
var zoomList:Array<Float> = [
0.5,
1,
2,
4,
8,
12,
16,
24
];
#else //The grid gets all black when over 1/12 snap
var zoomList:Array<Float> = [
0.5,
1,
2,
4,
8,
12
];
#end
private var blockPressWhileTypingOn:Array<FlxUIInputText> = [];
private var blockPressWhileScrolling:Array<FlxUIDropDownMenuCustom> = [];
var waveformSprite:FlxSprite;
var gridLayer:FlxTypedGroup<FlxSprite>;
override function create()
{
#if MODS_ALLOWED
Paths.destroyLoadedImages();
#end
#if desktop
// Updating Discord Rich Presence
DiscordClient.changePresence("Chart Editor", StringTools.replace(PlayState.SONG.song, '-', ' '));
#end
var bg:FlxSprite = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
bg.scrollFactor.set();
bg.color = 0xFF222222;
add(bg);
gridLayer = new FlxTypedGroup<FlxSprite>();
add(gridLayer);
waveformSprite = new FlxSprite(GRID_SIZE, 0).makeGraphic(FlxG.width, FlxG.height, 0x00FFFFFF);
add(waveformSprite);
var eventIcon:FlxSprite = new FlxSprite(-GRID_SIZE - 5, -90).loadGraphic(Paths.image('eventArrow'));
leftIcon = new HealthIcon('bf');
rightIcon = new HealthIcon('dad');
eventIcon.scrollFactor.set(1, 1);
leftIcon.scrollFactor.set(1, 1);
rightIcon.scrollFactor.set(1, 1);
eventIcon.setGraphicSize(30, 30);
leftIcon.setGraphicSize(0, 45);
rightIcon.setGraphicSize(0, 45);
add(eventIcon);
add(leftIcon);
add(rightIcon);
leftIcon.setPosition(GRID_SIZE + 10, -100);
rightIcon.setPosition(GRID_SIZE * 5.2, -100);
curRenderedSustains = new FlxTypedGroup<FlxSprite>();
curRenderedNotes = new FlxTypedGroup<Note>();
curRenderedNoteType = new FlxTypedGroup<FlxText>();
nextRenderedSustains = new FlxTypedGroup<FlxSprite>();
nextRenderedNotes = new FlxTypedGroup<Note>();
if (PlayState.SONG != null)
_song = PlayState.SONG;
else
{
_song = {
song: 'Test',
notes: [],
bpm: 150.0,
needsVoices: true,
arrowSkin: '',
splashSkin: '',
player1: 'bf',
player2: 'dad',
player3: 'gf',
speed: 1,
stage: 'stage',
validScore: false
};
}
if(curSection >= _song.notes.length) curSection = _song.notes.length - 1;
FlxG.mouse.visible = true;
FlxG.save.bind('funkin', 'ninjamuffin99');
tempBpm = _song.bpm;
addSection();
// sections = _song.notes;
currentSongName = Paths.formatToSongPath(_song.song);
loadAudioBuffer();
reloadGridLayer();
loadSong();
Conductor.changeBPM(_song.bpm);
Conductor.mapBPMChanges(_song);
bpmTxt = new FlxText(1000, 50, 0, "", 16);
bpmTxt.scrollFactor.set();
add(bpmTxt);
strumLine = new FlxSprite(0, 50).makeGraphic(Std.int(GRID_SIZE * 9), 4);
add(strumLine);
camPos = new FlxObject(0, 0, 1, 1);
camPos.setPosition(strumLine.x + CAM_OFFSET, strumLine.y);
dummyArrow = new FlxSprite().makeGraphic(GRID_SIZE, GRID_SIZE);
add(dummyArrow);
var tabs = [
{name: "Song", label: 'Song'},
{name: "Section", label: 'Section'},
{name: "Note", label: 'Note'},
{name: "Events", label: 'Events'},
{name: "Charting", label: 'Charting'},
];
UI_box = new FlxUITabMenu(null, tabs, true);
UI_box.resize(300, 400);
UI_box.x = FlxG.width / 2 + GRID_SIZE / 2;
UI_box.y = 25;
UI_box.scrollFactor.set();
var text:String =
"W/S or Mouse Wheel - Change Conductor's strum time
\nA or Left/D or Right - Go to the previous/next section
\nHold Shift to move 4x faster
\nHold Control and click on an arrow to select it
\nZ/X - Zoom in/out
\n
\nEsc - Test your chart inside Chart Editor
\nEnter - Play your chart
\nQ/E - Decrease/Increase Note Sustain Length
\nSpace - Stop/Resume song";
var tipTextArray:Array<String> = text.split('\n');
for (i in 0...tipTextArray.length) {
var tipText:FlxText = new FlxText(UI_box.x, UI_box.y + UI_box.height + 8, 0, tipTextArray[i], 16);
tipText.y += i * 14;
tipText.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, LEFT/*, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK*/);
//tipText.borderSize = 2;
tipText.scrollFactor.set();
add(tipText);
}
add(UI_box);
addSongUI();
addSectionUI();
addNoteUI();
addEventsUI();
addChartingUI();
updateHeads();
updateWaveform();
//UI_box.selected_tab = 4;
add(curRenderedSustains);
add(curRenderedNotes);
add(curRenderedNoteType);
add(nextRenderedSustains);
add(nextRenderedNotes);
if(lastSong != currentSongName) {
changeSection();
}
lastSong = currentSongName;
zoomTxt = new FlxText(10, 10, 0, "Zoom: 1x", 16);
zoomTxt.scrollFactor.set();
add(zoomTxt);
updateGrid();
super.create();
}
var check_mute_inst:FlxUICheckBox = null;
var playSoundBf:FlxUICheckBox = null;
var playSoundDad:FlxUICheckBox = null;
var UI_songTitle:FlxUIInputText;
var noteSkinInputText:FlxUIInputText;
var noteSplashesInputText:FlxUIInputText;
var stageDropDown:FlxUIDropDownMenuCustom;
function addSongUI():Void
{
UI_songTitle = new FlxUIInputText(10, 10, 70, _song.song, 8);
blockPressWhileTypingOn.push(UI_songTitle);
var check_voices = new FlxUICheckBox(10, 25, null, null, "Has voice track", 100);
check_voices.checked = _song.needsVoices;
// _song.needsVoices = check_voices.checked;
check_voices.callback = function()
{
_song.needsVoices = check_voices.checked;
trace('CHECKED!');
};
var saveButton:FlxButton = new FlxButton(110, 8, "Save", function()
{
saveLevel();
});
var reloadSong:FlxButton = new FlxButton(saveButton.x + 90, saveButton.y, "Reload Audio", function()
{
currentSongName = Paths.formatToSongPath(UI_songTitle.text);
loadSong();
loadAudioBuffer();
updateWaveform();
});
var reloadSongJson:FlxButton = new FlxButton(reloadSong.x, saveButton.y + 30, "Reload JSON", function()
{
loadJson(_song.song.toLowerCase());
});
var loadAutosaveBtn:FlxButton = new FlxButton(reloadSongJson.x, reloadSongJson.y + 30, 'Load Autosave', function()
{
PlayState.SONG = Song.parseJSONshit(FlxG.save.data.autosave);
MusicBeatState.resetState();
});
var loadEventJson:FlxButton = new FlxButton(loadAutosaveBtn.x, loadAutosaveBtn.y + 30, 'Load Events', function()
{
var songName:String = Paths.formatToSongPath(_song.song);
var file:String = Paths.json(songName + '/events');
#if sys
if (#if MODS_ALLOWED FileSystem.exists(Paths.modsJson(songName + '/events')) || #end FileSystem.exists(file))
#else
if (OpenFlAssets.exists(file))
#end
{
clearEvents();
var events:SwagSong = Song.loadFromJson('events', songName);
for (sec in 0...events.notes.length) {
for (noteId in 0...events.notes[sec].sectionNotes.length) {
var note:Array<Dynamic> = events.notes[sec].sectionNotes[noteId];
if(note != null && note[1] < 0) {
_song.notes[sec].sectionNotes.push([note[0], note[1], note[2], note[3], note[4]]);
}
}
}
changeSection(curSection);
}
});
var saveEvents:FlxButton = new FlxButton(110, reloadSongJson.y, 'Save Events', function ()
{
saveEvents();
});
var clear_events:FlxButton = new FlxButton(320, 310, 'Clear events', function()
{
clearEvents();
});
var clear_notes:FlxButton = new FlxButton(320, clear_events.y + 30, 'Clear notes', function()
{
for (sec in 0..._song.notes.length) {
var count:Int = 0;
while(count < _song.notes[sec].sectionNotes.length) {
var note:Array<Dynamic> = _song.notes[sec].sectionNotes[count];
if(note != null && note[1] > -1) {
_song.notes[sec].sectionNotes.remove(note);
} else {
count++;
}
}
}
updateGrid();
});
var stepperBPM:FlxUINumericStepper = new FlxUINumericStepper(10, 70, 1, 1, 1, 339, 1);
stepperBPM.value = Conductor.bpm;
stepperBPM.name = 'song_bpm';
var stepperSpeed:FlxUINumericStepper = new FlxUINumericStepper(10, stepperBPM.y + 35, 0.1, 1, 0.1, 10, 1);
stepperSpeed.value = _song.speed;
stepperSpeed.name = 'song_speed';
#if MODS_ALLOWED
var directories:Array<String> = [Paths.mods('characters/'), Paths.mods(Paths.currentModDirectory + '/characters/'), Paths.getPreloadPath('characters/')];
#else
var directories:Array<String> = [Paths.getPreloadPath('characters/')];
#end
var tempMap:Map<String, Bool> = new Map<String, Bool>();
var characters:Array<String> = CoolUtil.coolTextFile(Paths.txt('characterList'));
for (i in 0...characters.length) {
tempMap.set(characters[i], true);
}
#if MODS_ALLOWED
for (i in 0...directories.length) {
var directory:String = directories[i];
if(FileSystem.exists(directory)) {
for (file in FileSystem.readDirectory(directory)) {
var path = haxe.io.Path.join([directory, file]);
if (!FileSystem.isDirectory(path) && file.endsWith('.json')) {
var charToCheck:String = file.substr(0, file.length - 5);
if(!charToCheck.endsWith('-dead') && !tempMap.exists(charToCheck)) {
tempMap.set(charToCheck, true);
characters.push(charToCheck);
}
}
}
}
}
#end
var player1DropDown = new FlxUIDropDownMenuCustom(10, stepperSpeed.y + 45, FlxUIDropDownMenuCustom.makeStrIdLabelArray(characters, true), function(character:String)
{
_song.player1 = characters[Std.parseInt(character)];
updateHeads();
});
player1DropDown.selectedLabel = _song.player1;
blockPressWhileScrolling.push(player1DropDown);
var player3DropDown = new FlxUIDropDownMenuCustom(player1DropDown.x, player1DropDown.y + 40, FlxUIDropDownMenuCustom.makeStrIdLabelArray(characters, true), function(character:String)
{
_song.player3 = characters[Std.parseInt(character)];
updateHeads();
});
player3DropDown.selectedLabel = _song.player3;
blockPressWhileScrolling.push(player3DropDown);
var player2DropDown = new FlxUIDropDownMenuCustom(player1DropDown.x, player3DropDown.y + 40, FlxUIDropDownMenuCustom.makeStrIdLabelArray(characters, true), function(character:String)
{
_song.player2 = characters[Std.parseInt(character)];
updateHeads();
});
player2DropDown.selectedLabel = _song.player2;
blockPressWhileScrolling.push(player2DropDown);
#if MODS_ALLOWED
var directories:Array<String> = [Paths.mods('stages/'), Paths.mods(Paths.currentModDirectory + '/stages/'), Paths.getPreloadPath('stages/')];
#else
var directories:Array<String> = [Paths.getPreloadPath('stages/')];
#end
tempMap.clear();
var stageFile:Array<String> = CoolUtil.coolTextFile(Paths.txt('stageList'));
var stages:Array<String> = [];
for (i in 0...stageFile.length) { //Prevent duplicates
var stageToCheck:String = stageFile[i];
if(!tempMap.exists(stageToCheck)) {
stages.push(stageToCheck);
}
tempMap.set(stageToCheck, true);
}
#if MODS_ALLOWED
for (i in 0...directories.length) {
var directory:String = directories[i];
if(FileSystem.exists(directory)) {
for (file in FileSystem.readDirectory(directory)) {
var path = haxe.io.Path.join([directory, file]);
if (!FileSystem.isDirectory(path) && file.endsWith('.json')) {
var stageToCheck:String = file.substr(0, file.length - 5);
if(!tempMap.exists(stageToCheck)) {
tempMap.set(stageToCheck, true);
stages.push(stageToCheck);
}
}
}
}
}
#end
if(stages.length < 1) stages.push('stage');
stageDropDown = new FlxUIDropDownMenuCustom(player1DropDown.x + 140, player1DropDown.y, FlxUIDropDownMenuCustom.makeStrIdLabelArray(stages, true), function(character:String)
{
_song.stage = stages[Std.parseInt(character)];
});
stageDropDown.selectedLabel = _song.stage;
blockPressWhileScrolling.push(stageDropDown);
var skin = PlayState.SONG.arrowSkin;
if(skin == null) skin = '';
noteSkinInputText = new FlxUIInputText(player2DropDown.x, player2DropDown.y + 50, 150, skin, 8);
blockPressWhileTypingOn.push(noteSkinInputText);
noteSplashesInputText = new FlxUIInputText(noteSkinInputText.x, noteSkinInputText.y + 35, 150, _song.splashSkin, 8);
blockPressWhileTypingOn.push(noteSplashesInputText);
var reloadNotesButton:FlxButton = new FlxButton(noteSplashesInputText.x + 5, noteSplashesInputText.y + 20, 'Change Notes', function() {
_song.arrowSkin = noteSkinInputText.text;
updateGrid();
});
var tab_group_song = new FlxUI(null, UI_box);
tab_group_song.name = "Song";
tab_group_song.add(UI_songTitle);
tab_group_song.add(check_voices);
tab_group_song.add(clear_events);
tab_group_song.add(clear_notes);
tab_group_song.add(saveButton);
tab_group_song.add(saveEvents);
tab_group_song.add(reloadSong);
tab_group_song.add(reloadSongJson);
tab_group_song.add(loadAutosaveBtn);
tab_group_song.add(loadEventJson);
tab_group_song.add(stepperBPM);
tab_group_song.add(stepperSpeed);
tab_group_song.add(reloadNotesButton);
tab_group_song.add(noteSkinInputText);
tab_group_song.add(noteSplashesInputText);
tab_group_song.add(new FlxText(stepperBPM.x, stepperBPM.y - 15, 0, 'Song BPM:'));
tab_group_song.add(new FlxText(stepperSpeed.x, stepperSpeed.y - 15, 0, 'Song Speed:'));
tab_group_song.add(new FlxText(player2DropDown.x, player2DropDown.y - 15, 0, 'Opponent:'));
tab_group_song.add(new FlxText(player3DropDown.x, player3DropDown.y - 15, 0, 'Girlfriend:'));
tab_group_song.add(new FlxText(player1DropDown.x, player1DropDown.y - 15, 0, 'Boyfriend:'));
tab_group_song.add(new FlxText(stageDropDown.x, stageDropDown.y - 15, 0, 'Stage:'));
tab_group_song.add(new FlxText(noteSkinInputText.x, noteSkinInputText.y - 15, 0, 'Note Texture:'));
tab_group_song.add(new FlxText(noteSplashesInputText.x, noteSplashesInputText.y - 15, 0, 'Note Splashes Texture:'));
tab_group_song.add(player2DropDown);
tab_group_song.add(player3DropDown);
tab_group_song.add(player1DropDown);
tab_group_song.add(stageDropDown);
UI_box.addGroup(tab_group_song);
FlxG.camera.follow(camPos);
}
var stepperLength:FlxUINumericStepper;
var check_mustHitSection:FlxUICheckBox;
var check_changeBPM:FlxUICheckBox;
var stepperSectionBPM:FlxUINumericStepper;
var check_altAnim:FlxUICheckBox;
var sectionToCopy:Int = 0;
var notesCopied:Array<Dynamic>;
function addSectionUI():Void
{
var tab_group_section = new FlxUI(null, UI_box);
tab_group_section.name = 'Section';
stepperLength = new FlxUINumericStepper(10, 10, 4, 0, 0, 999, 0);
stepperLength.value = _song.notes[curSection].lengthInSteps;
stepperLength.name = 'section_length';
check_mustHitSection = new FlxUICheckBox(10, 30, null, null, "Must hit section", 100);
check_mustHitSection.name = 'check_mustHit';
check_mustHitSection.checked = _song.notes[curSection].mustHitSection;
// _song.needsVoices = check_mustHit.checked;
check_altAnim = new FlxUICheckBox(10, 60, null, null, "Alt Animation", 100);
check_altAnim.checked = _song.notes[curSection].altAnim;
check_altAnim.name = 'check_altAnim';
check_changeBPM = new FlxUICheckBox(10, 90, null, null, 'Change BPM', 100);
check_changeBPM.checked = _song.notes[curSection].changeBPM;
check_changeBPM.name = 'check_changeBPM';
stepperSectionBPM = new FlxUINumericStepper(10, 110, 1, Conductor.bpm, 0, 999, 1);
if(check_changeBPM.checked) {
stepperSectionBPM.value = _song.notes[curSection].bpm;
} else {
stepperSectionBPM.value = Conductor.bpm;
}
stepperSectionBPM.name = 'section_bpm';
var copyButton:FlxButton = new FlxButton(10, 150, "Copy Section", function()
{
notesCopied = [];
sectionToCopy = curSection;
for (i in 0..._song.notes[curSection].sectionNotes.length)
{
var note:Array<Dynamic> = _song.notes[curSection].sectionNotes[i];
notesCopied.push(note);
}
});
var pasteButton:FlxButton = new FlxButton(10, 180, "Paste Section", function()
{
var addToTime:Float = Conductor.stepCrochet * (_song.notes[curSection].lengthInSteps * (curSection - sectionToCopy));
trace('Time to add: ' + addToTime);
for (note in notesCopied)
{
var copiedNote:Array<Dynamic> = [];
if(note[4] != null) {
copiedNote = [note[0] + addToTime, note[1], note[2], note[3], note[4]];
} else {
copiedNote = [note[0] + addToTime, note[1], note[2], note[3]];
}
_song.notes[curSection].sectionNotes.push(copiedNote);
}
updateGrid();
});
var clearSectionButton:FlxButton = new FlxButton(10, 210, "Clear", function()
{
_song.notes[curSection].sectionNotes = [];
updateGrid();
});
var swapSection:FlxButton = new FlxButton(10, 240, "Swap section", function()
{
for (i in 0..._song.notes[curSection].sectionNotes.length)
{
var note:Array<Dynamic> = _song.notes[curSection].sectionNotes[i];
if(note[1] > -1) {
note[1] = (note[1] + 4) % 8;
_song.notes[curSection].sectionNotes[i] = note;
}
}
updateGrid();
});
var stepperCopy:FlxUINumericStepper = new FlxUINumericStepper(110, 276, 1, 1, -999, 999, 0);
var copyLastButton:FlxButton = new FlxButton(10, 270, "Copy last section", function()
{
var value:Int = Std.int(stepperCopy.value);
var daSec = FlxMath.maxInt(curSection, value);
for (note in _song.notes[daSec - value].sectionNotes)
{
var strum = note[0] + Conductor.stepCrochet * (_song.notes[daSec].lengthInSteps * value);
var copiedNote:Array<Dynamic> = [strum, note[1], note[2], note[3]];
if(note[1] < 0) {
copiedNote = [strum, note[1], note[2], note[3], note[4]];
}
_song.notes[daSec].sectionNotes.push(copiedNote);
}
updateGrid();
});
copyLastButton.setGraphicSize(80, 30);
copyLastButton.updateHitbox();
tab_group_section.add(stepperLength);
tab_group_section.add(stepperSectionBPM);
tab_group_section.add(check_mustHitSection);
tab_group_section.add(check_altAnim);
tab_group_section.add(check_changeBPM);
tab_group_section.add(copyButton);
tab_group_section.add(pasteButton);
tab_group_section.add(clearSectionButton);
tab_group_section.add(swapSection);
tab_group_section.add(stepperCopy);
tab_group_section.add(copyLastButton);
UI_box.addGroup(tab_group_section);
}
var stepperSusLength:FlxUINumericStepper;
var strumTimeInputText:FlxUIInputText; //I wanted to use a stepper but we can't scale these as far as i know :(
var noteTypeDropDown:FlxUIDropDownMenuCustom;
var currentType:Int = 0;
function addNoteUI():Void
{
var tab_group_note = new FlxUI(null, UI_box);
tab_group_note.name = 'Note';
stepperSusLength = new FlxUINumericStepper(10, 25, Conductor.stepCrochet / 2, 0, 0, Conductor.stepCrochet * 32);
stepperSusLength.value = 0;
stepperSusLength.name = 'note_susLength';
strumTimeInputText = new FlxUIInputText(10, 65, 180, "0");
tab_group_note.add(strumTimeInputText);
blockPressWhileTypingOn.push(strumTimeInputText);
var key:Int = 0;
var displayNameList:Array<String> = [];
while (key < noteTypeList.length) {
displayNameList.push(noteTypeList[key]);
noteTypeMap.set(noteTypeList[key], key);
noteTypeIntMap.set(key, noteTypeList[key]);
key++;
}
#if LUA_ALLOWED
var directories:Array<String> = [Paths.mods('custom_notetypes/'), Paths.mods(Paths.currentModDirectory + '/custom_notetypes/')];
for (i in 0...directories.length) {
var directory:String = directories[i];
if(FileSystem.exists(directory)) {
for (file in FileSystem.readDirectory(directory)) {
var path = haxe.io.Path.join([directory, file]);
if (!FileSystem.isDirectory(path) && file.endsWith('.lua')) {
var fileToCheck:String = file.substr(0, file.length - 4);
if(!noteTypeMap.exists(fileToCheck)) {
displayNameList.push(fileToCheck);
noteTypeMap.set(fileToCheck, key);
noteTypeIntMap.set(key, fileToCheck);
key++;
}
}
}
}
}
#end
for (i in 1...displayNameList.length) {
displayNameList[i] = i + '. ' + displayNameList[i];
}
noteTypeDropDown = new FlxUIDropDownMenuCustom(10, 105, FlxUIDropDownMenuCustom.makeStrIdLabelArray(displayNameList, true), function(character:String)
{
currentType = Std.parseInt(character);
if(curSelectedNote != null && curSelectedNote[1] > -1) {
curSelectedNote[3] = noteTypeIntMap.get(currentType);
updateGrid();
}
});
blockPressWhileScrolling.push(noteTypeDropDown);
tab_group_note.add(new FlxText(10, 10, 0, 'Sustain length:'));
tab_group_note.add(new FlxText(10, 50, 0, 'Strum time (in miliseconds):'));
tab_group_note.add(new FlxText(10, 90, 0, 'Note type:'));
tab_group_note.add(stepperSusLength);
tab_group_note.add(strumTimeInputText);
tab_group_note.add(noteTypeDropDown);
UI_box.addGroup(tab_group_note);
}
var eventDropDown:FlxUIDropDownMenuCustom;
var descText:FlxText;
function addEventsUI():Void
{
var tab_group_event = new FlxUI(null, UI_box);
tab_group_event.name = 'Events';
#if LUA_ALLOWED
var eventPushedMap:Map<String, Bool> = new Map<String, Bool>();
var directories:Array<String> = [Paths.mods('custom_events/'), Paths.mods(Paths.currentModDirectory + '/custom_events/')];
for (i in 0...directories.length) {
var directory:String = directories[i];
if(FileSystem.exists(directory)) {
for (file in FileSystem.readDirectory(directory)) {
var path = haxe.io.Path.join([directory, file]);
if (!FileSystem.isDirectory(path) && file != 'readme.txt' && file.endsWith('.txt')) {
var fileToCheck:String = file.substr(0, file.length - 4);
if(!eventPushedMap.exists(fileToCheck)) {
eventPushedMap.set(fileToCheck, true);
eventStuff.push([fileToCheck, File.getContent(path)]);
}
}
}
}
}
eventPushedMap.clear();
eventPushedMap = null;
#end
descText = new FlxText(20, 200, 0, eventStuff[0][0]);
var leEvents:Array<String> = [];
for (i in 0...eventStuff.length) {
leEvents.push(eventStuff[i][0]);
}
var text:FlxText = new FlxText(20, 30, 0, "Event:");
tab_group_event.add(text);
eventDropDown = new FlxUIDropDownMenuCustom(20, 50, FlxUIDropDownMenuCustom.makeStrIdLabelArray(leEvents, true), function(pressed:String) {
var selectedEvent:Int = Std.parseInt(pressed);
descText.text = eventStuff[selectedEvent][1];
if(curSelectedNote != null) {
curSelectedNote[2] = eventStuff[selectedEvent][0];
updateGrid();
}
});
blockPressWhileScrolling.push(eventDropDown);
var text:FlxText = new FlxText(20, 90, 0, "Value 1:");
tab_group_event.add(text);
value1InputText = new FlxUIInputText(20, 110, 100, "");
blockPressWhileTypingOn.push(value1InputText);
var text:FlxText = new FlxText(20, 130, 0, "Value 2:");
tab_group_event.add(text);
value2InputText = new FlxUIInputText(20, 150, 100, "");
blockPressWhileTypingOn.push(value2InputText);
tab_group_event.add(descText);
tab_group_event.add(value1InputText);
tab_group_event.add(value2InputText);
tab_group_event.add(eventDropDown);
UI_box.addGroup(tab_group_event);
}
var metronome:FlxUICheckBox;
var metronomeStepper:FlxUINumericStepper;
var metronomeOffsetStepper:FlxUINumericStepper;
var disableAutoScrolling:FlxUICheckBox;
#if desktop
var waveformEnabled:FlxUICheckBox;
var waveformUseInstrumental:FlxUICheckBox;
#end
var instVolume:FlxUINumericStepper;
var voicesVolume:FlxUINumericStepper;
function addChartingUI() {
var tab_group_chart = new FlxUI(null, UI_box);
tab_group_chart.name = 'Charting';
#if desktop
waveformEnabled = new FlxUICheckBox(10, 90, null, null, "Visible Waveform", 100);
waveformEnabled.checked = false;
waveformEnabled.callback = function()
{
updateWaveform();
};
waveformUseInstrumental = new FlxUICheckBox(waveformEnabled.x + 120, waveformEnabled.y, null, null, "Waveform for Instrumental", 100);
waveformUseInstrumental.checked = false;
waveformUseInstrumental.callback = function()
{
updateWaveform();
};
#end
check_mute_inst = new FlxUICheckBox(10, 310, null, null, "Mute Instrumental (in editor)", 100);
check_mute_inst.checked = false;
check_mute_inst.callback = function()
{
var vol:Float = 1;
if (check_mute_inst.checked)
vol = 0;
FlxG.sound.music.volume = vol;
};
var check_mute_vocals = new FlxUICheckBox(check_mute_inst.x + 120, check_mute_inst.y, null, null, "Mute Vocals (in editor)", 100);
check_mute_vocals.checked = false;
check_mute_vocals.callback = function()
{
if(vocals != null) {
var vol:Float = 1;
if (check_mute_vocals.checked)
vol = 0;
vocals.volume = vol;
}
};
playSoundBf = new FlxUICheckBox(check_mute_inst.x, check_mute_vocals.y + 30, null, null, 'Play Sound (Boyfriend notes)', 100);
playSoundBf.checked = false;
playSoundDad = new FlxUICheckBox(check_mute_inst.x + 120, playSoundBf.y, null, null, 'Play Sound (Opponent notes)', 100);
playSoundDad.checked = false;
metronome = new FlxUICheckBox(10, 15, null, null, "Metronome Enabled", 100);
metronomeStepper = new FlxUINumericStepper(15, 55, 5, _song.bpm, 1, 1500, 1);
metronomeOffsetStepper = new FlxUINumericStepper(metronomeStepper.x + 100, metronomeStepper.y, 25, 0, 0, 1000, 1);
disableAutoScrolling = new FlxUICheckBox(metronome.x + 120, metronome.y, null, null, "Disable Autoscroll (Not Recommended)", 120);
instVolume = new FlxUINumericStepper(metronomeStepper.x, 270, 0.1, 1, 0, 1, 1);
instVolume.value = FlxG.sound.music.volume;
instVolume.name = 'inst_volume';
voicesVolume = new FlxUINumericStepper(instVolume.x + 100, instVolume.y, 0.1, 1, 0, 1, 1);
voicesVolume.value = vocals.volume;
voicesVolume.name = 'voices_volume';
tab_group_chart.add(new FlxText(metronomeStepper.x, metronomeStepper.y - 15, 0, 'BPM:'));
tab_group_chart.add(new FlxText(metronomeOffsetStepper.x, metronomeOffsetStepper.y - 15, 0, 'Offset (ms):'));
tab_group_chart.add(new FlxText(instVolume.x, instVolume.y - 15, 0, 'Inst Volume'));
tab_group_chart.add(new FlxText(voicesVolume.x, voicesVolume.y - 15, 0, 'Voices Volume'));
tab_group_chart.add(metronome);
tab_group_chart.add(disableAutoScrolling);
tab_group_chart.add(metronomeStepper);
tab_group_chart.add(metronomeOffsetStepper);
#if desktop
tab_group_chart.add(waveformEnabled);
tab_group_chart.add(waveformUseInstrumental);
#end
tab_group_chart.add(instVolume);
tab_group_chart.add(voicesVolume);
tab_group_chart.add(check_mute_inst);
tab_group_chart.add(check_mute_vocals);
tab_group_chart.add(playSoundBf);
tab_group_chart.add(playSoundDad);
UI_box.addGroup(tab_group_chart);
}
function loadSong():Void
{
if (FlxG.sound.music != null)
{
FlxG.sound.music.stop();
// vocals.stop();
}
var file:Dynamic = Paths.voices(currentSongName);
vocals = new FlxSound();
if (Std.isOfType(file, Sound) || OpenFlAssets.exists(file)) {
vocals.loadEmbedded(file);
FlxG.sound.list.add(vocals);
}
generateSong();
FlxG.sound.music.pause();
Conductor.songPosition = sectionStartTime();
FlxG.sound.music.time = Conductor.songPosition;
}
function generateSong() {
FlxG.sound.playMusic(Paths.inst(currentSongName), 0.6, false);
if (instVolume != null) FlxG.sound.music.volume = instVolume.value;
if (check_mute_inst != null && check_mute_inst.checked) FlxG.sound.music.volume = 0;
FlxG.sound.music.onComplete = function()
{
generateSong();
FlxG.sound.music.pause();
Conductor.songPosition = 0;
if(vocals != null) {
vocals.play();
vocals.pause();
vocals.time = 0;
}
changeSection();
curSection = 0;
updateGrid();
updateSectionUI();
};
}
function generateUI():Void
{
while (bullshitUI.members.length > 0)
{
bullshitUI.remove(bullshitUI.members[0], true);
}
// general shit
var title:FlxText = new FlxText(UI_box.x + 20, UI_box.y + 20, 0);
bullshitUI.add(title);
/*
var loopCheck = new FlxUICheckBox(UI_box.x + 10, UI_box.y + 50, null, null, "Loops", 100, ['loop check']);
loopCheck.checked = curNoteSelected.doesLoop;
tooltips.add(loopCheck, {title: 'Section looping', body: "Whether or not it's a simon says style section", style: tooltipType});
bullshitUI.add(loopCheck);
*/
}
override function getEvent(id:String, sender:Dynamic, data:Dynamic, ?params:Array<Dynamic>)
{
if (id == FlxUICheckBox.CLICK_EVENT)
{
var check:FlxUICheckBox = cast sender;
var label = check.getLabel().text;
switch (label)
{
case 'Must hit section':
_song.notes[curSection].mustHitSection = check.checked;
updateGrid();
updateHeads();
case 'Change BPM':
_song.notes[curSection].changeBPM = check.checked;
FlxG.log.add('changed bpm shit');
case "Alt Animation":
_song.notes[curSection].altAnim = check.checked;
}
}
else if (id == FlxUINumericStepper.CHANGE_EVENT && (sender is FlxUINumericStepper))
{
var nums:FlxUINumericStepper = cast sender;
var wname = nums.name;
FlxG.log.add(wname);
if (wname == 'section_length')
{
_song.notes[curSection].lengthInSteps = Std.int(nums.value);
updateGrid();
}
else if (wname == 'song_speed')
{
_song.speed = nums.value;
}
else if (wname == 'song_bpm')
{
tempBpm = nums.value;
Conductor.mapBPMChanges(_song);
Conductor.changeBPM(nums.value);
}
else if (wname == 'note_susLength')
{
if(curSelectedNote != null && curSelectedNote[1] > -1) {
curSelectedNote[2] = nums.value;
updateGrid();
} else {
sender.value = 0;
}
}
else if (wname == 'section_bpm')
{
_song.notes[curSection].bpm = nums.value;
updateGrid();
}
else if (wname == 'inst_volume')
{
FlxG.sound.music.volume = nums.value;
}
else if (wname == 'voices_volume')
{
vocals.volume = nums.value;
}
}
else if(id == FlxUIInputText.CHANGE_EVENT && (sender is FlxUIInputText)) {
if(sender == noteSplashesInputText) {
_song.splashSkin = noteSplashesInputText.text;
}
else if(curSelectedNote != null)
{
if(sender == value1InputText) {
curSelectedNote[3] = value1InputText.text;
updateGrid();
}
else if(sender == value2InputText) {
curSelectedNote[4] = value2InputText.text;
updateGrid();
}
else if(sender == strumTimeInputText) {
var value:Float = Std.parseFloat(strumTimeInputText.text);
if(Math.isNaN(value)) value = 0;
curSelectedNote[0] = value;
updateGrid();
}
}
}
// FlxG.log.add(id + " WEED " + sender + " WEED " + data + " WEED " + params);
}
var updatedSection:Bool = false;
/* this function got owned LOL
function lengthBpmBullshit():Float
{
if (_song.notes[curSection].changeBPM)
return _song.notes[curSection].lengthInSteps * (_song.notes[curSection].bpm / _song.bpm);
else
return _song.notes[curSection].lengthInSteps;
}*/
function sectionStartTime(add:Int = 0):Float
{
var daBPM:Float = _song.bpm;
var daPos:Float = 0;
for (i in 0...curSection + add)
{
if (_song.notes[i].changeBPM)
{
daBPM = _song.notes[i].bpm;
}
daPos += 4 * (1000 * 60 / daBPM);
}
return daPos;
}
var lastConductorPos:Float;
var colorSine:Float = 0;
override function update(elapsed:Float)
{
curStep = recalculateSteps();
if(FlxG.sound.music.time < 0) {
FlxG.sound.music.pause();
FlxG.sound.music.time = 0;
}
else if(FlxG.sound.music.time > FlxG.sound.music.length) {
FlxG.sound.music.pause();
FlxG.sound.music.time = 0;
changeSection();
}
Conductor.songPosition = FlxG.sound.music.time;
_song.song = UI_songTitle.text;
strumLine.y = getYfromStrum((Conductor.songPosition - sectionStartTime()) / zoomList[curZoom] % (Conductor.stepCrochet * _song.notes[curSection].lengthInSteps));
camPos.y = strumLine.y;
if(!disableAutoScrolling.checked) {
if (strumLine.y > (gridBG.height / 2))
{
trace(curStep);
trace((_song.notes[curSection].lengthInSteps) * (curSection + 1));
trace('DUMBSHIT');
if (_song.notes[curSection + 1] == null)
{
addSection();
}
changeSection(curSection + 1, false);
} else if(strumLine.y < -10) {
changeSection(curSection - 1, false);
}
}
FlxG.watch.addQuick('daBeat', curBeat);
FlxG.watch.addQuick('daStep', curStep);
if (FlxG.mouse.justPressed)
{
if (FlxG.mouse.overlaps(curRenderedNotes))
{
curRenderedNotes.forEachAlive(function(note:Note)
{
if (FlxG.mouse.overlaps(note))
{
if (FlxG.keys.pressed.CONTROL)
{
selectNote(note);
}
else
{
trace('tryin to delete note...');
deleteNote(note);
}
}
});
}
else
{
if (FlxG.mouse.x > gridBG.x
&& FlxG.mouse.x < gridBG.x + gridBG.width
&& FlxG.mouse.y > gridBG.y
&& FlxG.mouse.y < gridBG.y + (GRID_SIZE * _song.notes[curSection].lengthInSteps) * zoomList[curZoom])
{
FlxG.log.add('added note');
addNote();
}
}
}
if (FlxG.mouse.x > gridBG.x
&& FlxG.mouse.x < gridBG.x + gridBG.width
&& FlxG.mouse.y > gridBG.y
&& FlxG.mouse.y < gridBG.y + (GRID_SIZE * _song.notes[curSection].lengthInSteps) * zoomList[curZoom])
{
dummyArrow.x = Math.floor(FlxG.mouse.x / GRID_SIZE) * GRID_SIZE;
if (FlxG.keys.pressed.SHIFT)
dummyArrow.y = FlxG.mouse.y;
else
dummyArrow.y = Math.floor(FlxG.mouse.y / GRID_SIZE) * GRID_SIZE;
}
var blockInput:Bool = false;
for (inputText in blockPressWhileTypingOn) {
if(inputText.hasFocus) {
FlxG.sound.muteKeys = [];
FlxG.sound.volumeDownKeys = [];
FlxG.sound.volumeUpKeys = [];
blockInput = true;
break;
}
}
if(!blockInput) {
FlxG.sound.muteKeys = TitleState.muteKeys;
FlxG.sound.volumeDownKeys = TitleState.volumeDownKeys;
FlxG.sound.volumeUpKeys = TitleState.volumeUpKeys;
for (dropDownMenu in blockPressWhileScrolling) {
if(dropDownMenu.dropPanel.visible) {
blockInput = true;
break;
}
}
}
if (!blockInput)
{
if (FlxG.keys.justPressed.ESCAPE)
{
autosaveSong();
LoadingState.loadAndSwitchState(new editors.EditorPlayState(sectionStartTime()));
}
if (FlxG.keys.justPressed.ENTER)
{
autosaveSong();
FlxG.mouse.visible = false;
PlayState.SONG = _song;
FlxG.sound.music.stop();
if(vocals != null) vocals.stop();
//if(_song.stage == null) _song.stage = stageDropDown.selectedLabel;
StageData.loadDirectory(_song);
LoadingState.loadAndSwitchState(new PlayState());
}
if(curSelectedNote != null && curSelectedNote[1] > -1) {
if (FlxG.keys.justPressed.E)
{
changeNoteSustain(Conductor.stepCrochet);
}
if (FlxG.keys.justPressed.Q)
{
changeNoteSustain(-Conductor.stepCrochet);
}
}
if(FlxG.keys.justPressed.Z && curZoom > 0) {
--curZoom;
updateZoom();
}
if(FlxG.keys.justPressed.X && curZoom < zoomList.length-1) {
curZoom++;
updateZoom();
}
if (FlxG.keys.justPressed.TAB)
{
if (FlxG.keys.pressed.SHIFT)
{
UI_box.selected_tab -= 1;
if (UI_box.selected_tab < 0)
UI_box.selected_tab = 2;
}
else
{
UI_box.selected_tab += 1;
if (UI_box.selected_tab >= 3)
UI_box.selected_tab = 0;
}
}
if (FlxG.keys.justPressed.SPACE)
{
if (FlxG.sound.music.playing)
{
FlxG.sound.music.pause();
if(vocals != null) vocals.pause();
}
else
{
if(vocals != null) {
vocals.play();
vocals.pause();
vocals.time = FlxG.sound.music.time;
vocals.play();
}
FlxG.sound.music.play();
}
}
if (FlxG.keys.justPressed.R)
{
if (FlxG.keys.pressed.SHIFT)
resetSection(true);
else
resetSection();
}
if (FlxG.mouse.wheel != 0)
{
FlxG.sound.music.pause();
FlxG.sound.music.time -= (FlxG.mouse.wheel * Conductor.stepCrochet * 0.4);
if(vocals != null) {
vocals.pause();
vocals.time = FlxG.sound.music.time;
}
}
if (FlxG.keys.pressed.W || FlxG.keys.pressed.S)
{
FlxG.sound.music.pause();
var holdingShift:Float = 1;
if (FlxG.keys.pressed.CONTROL) holdingShift = 0.25;
else if (FlxG.keys.pressed.SHIFT) holdingShift = 4;
var daTime:Float = 700 * FlxG.elapsed * holdingShift;
if (FlxG.keys.pressed.W)
{
FlxG.sound.music.time -= daTime;
}
else
FlxG.sound.music.time += daTime;
if(vocals != null) {
vocals.pause();
vocals.time = FlxG.sound.music.time;
}
}
var shiftThing:Int = 1;
if (FlxG.keys.pressed.SHIFT)
shiftThing = 4;
if (FlxG.keys.justPressed.RIGHT || FlxG.keys.justPressed.D)
changeSection(curSection + shiftThing);
if (FlxG.keys.justPressed.LEFT || FlxG.keys.justPressed.A) {
if(curSection <= 0) {
changeSection(_song.notes.length-1);
} else {
changeSection(curSection - shiftThing);
}
}
} else if (FlxG.keys.justPressed.ENTER) {
for (i in 0...blockPressWhileTypingOn.length) {
if(blockPressWhileTypingOn[i].hasFocus) {
blockPressWhileTypingOn[i].hasFocus = false;
}
}
}
_song.bpm = tempBpm;
if(FlxG.sound.music.time < 0) {
FlxG.sound.music.pause();
FlxG.sound.music.time = 0;
}
else if(FlxG.sound.music.time > FlxG.sound.music.length) {
FlxG.sound.music.pause();
FlxG.sound.music.time = 0;
changeSection();
}
Conductor.songPosition = FlxG.sound.music.time;
strumLine.y = getYfromStrum((Conductor.songPosition - sectionStartTime()) / zoomList[curZoom] % (Conductor.stepCrochet * _song.notes[curSection].lengthInSteps));
camPos.y = strumLine.y;
bpmTxt.text =
Std.string(FlxMath.roundDecimal(Conductor.songPosition / 1000, 2)) + " / " + Std.string(FlxMath.roundDecimal(FlxG.sound.music.length / 1000, 2)) +
"\nSection: " + curSection +
"\n\nBeat: " + curBeat +
"\n\nStep: " + curStep;
var playedSound:Array<Bool> = [false, false, false, false]; //Prevents earrape GF ahegao sounds
curRenderedNotes.forEachAlive(function(note:Note) {
note.alpha = 1;
if(curSelectedNote != null) {
var noteDataToCheck:Int = note.noteData;
if(noteDataToCheck > -1 && note.mustPress != _song.notes[curSection].mustHitSection) noteDataToCheck += 4;
if (curSelectedNote[0] == note.strumTime && curSelectedNote[1] == noteDataToCheck)
{
colorSine += 180 * elapsed;
var colorVal:Float = 0.7 + Math.sin((Math.PI * colorSine) / 180) * 0.3;
note.color = FlxColor.fromRGBFloat(colorVal, colorVal, colorVal, 0.999); //Alpha can't be 100% or the color won't be updated for some reason, guess i will die
}
}
if(note.strumTime <= Conductor.songPosition) {
note.alpha = 0.4;
if(note.strumTime > lastConductorPos && ((playSoundBf.checked && note.mustPress) || (playSoundDad.checked && !note.mustPress)) && FlxG.sound.music.playing && note.noteData > -1) {
var data:Int = note.noteData % 4;
if(!playedSound[data]) {
var soundToPlay = 'ChartingTick';
if(_song.player1 == 'gf') { //Easter egg
soundToPlay = 'GF_' + Std.string(data + 1);
}
FlxG.sound.play(Paths.sound(soundToPlay));
playedSound[data] = true;
}
}
}
});
if(metronome.checked && lastConductorPos != Conductor.songPosition) {
var metroInterval:Float = 60 / metronomeStepper.value;
var metroStep:Int = Math.floor(((Conductor.songPosition + metronomeOffsetStepper.value) / metroInterval) / 1000);
var lastMetroStep:Int = Math.floor(((lastConductorPos + metronomeOffsetStepper.value) / metroInterval) / 1000);
if(metroStep != lastMetroStep) {
FlxG.sound.play(Paths.sound('Metronome_Tick'));
//trace('Ticked');
}
}
lastConductorPos = Conductor.songPosition;
super.update(elapsed);
}
function updateZoom() {
zoomTxt.text = 'Zoom: ' + zoomList[curZoom] + 'x';
reloadGridLayer();
}
function loadAudioBuffer() {
if(audioBuffers[0] != null) {
audioBuffers[0].dispose();
}
audioBuffers[0] = null;
#if MODS_ALLOWED
if(FileSystem.exists(Paths.modFolders('songs/' + currentSongName + '/Inst.ogg'))) {
audioBuffers[0] = AudioBuffer.fromFile(Paths.modFolders('songs/' + currentSongName + '/Inst.ogg'));
//trace('Custom vocals found');
}
else { #end
var leVocals:Dynamic = Paths.inst(currentSongName);
if (!Std.isOfType(leVocals, Sound) && OpenFlAssets.exists(leVocals)) { //Vanilla inst
audioBuffers[0] = AudioBuffer.fromFile('./' + leVocals.substr(6));
//trace('Inst found');
}
#if MODS_ALLOWED
}
#end
if(audioBuffers[1] != null) {
audioBuffers[1].dispose();
}
audioBuffers[1] = null;
#if MODS_ALLOWED
if(FileSystem.exists(Paths.modFolders('songs/' + currentSongName + '/Voices.ogg'))) {
audioBuffers[1] = AudioBuffer.fromFile(Paths.modFolders('songs/' + currentSongName + '/Voices.ogg'));
//trace('Custom vocals found');
} else { #end
var leVocals:Dynamic = Paths.voices(currentSongName);
if (!Std.isOfType(leVocals, Sound) && OpenFlAssets.exists(leVocals)) { //Vanilla voices
audioBuffers[1] = AudioBuffer.fromFile('./' + leVocals.substr(6));
//trace('Voices found, LETS FUCKING GOOOO');
}
#if MODS_ALLOWED
}
#end
}
function reloadGridLayer() {
gridLayer.clear();
gridBG = FlxGridOverlay.create(GRID_SIZE, GRID_SIZE, GRID_SIZE * 9, Std.int(GRID_SIZE * 32 * zoomList[curZoom]));
gridLayer.add(gridBG);
#if desktop
if(waveformEnabled != null) {
updateWaveform();
}
#end
var gridBlack:FlxSprite = new FlxSprite(0, gridBG.height / 2).makeGraphic(Std.int(GRID_SIZE * 9), Std.int(gridBG.height / 2), FlxColor.BLACK);
gridBlack.alpha = 0.4;
gridLayer.add(gridBlack);
var gridBlackLine:FlxSprite = new FlxSprite(gridBG.x + gridBG.width - (GRID_SIZE * 4)).makeGraphic(2, Std.int(gridBG.height), FlxColor.BLACK);
gridLayer.add(gridBlackLine);
gridBlackLine = new FlxSprite(gridBG.x + GRID_SIZE).makeGraphic(2, Std.int(gridBG.height), FlxColor.BLACK);
gridLayer.add(gridBlackLine);
updateGrid();
}
var waveformPrinted:Bool = true;
var audioBuffers:Array<AudioBuffer> = [null, null];
function updateWaveform() {
#if desktop
if(waveformPrinted) {
waveformSprite.makeGraphic(Std.int(GRID_SIZE * 8), Std.int(gridBG.height), 0x00FFFFFF);
waveformSprite.pixels.fillRect(new Rectangle(0, 0, gridBG.width, gridBG.height), 0x00FFFFFF);
}
waveformPrinted = false;
var checkForVoices:Int = 1;
if(waveformUseInstrumental.checked) checkForVoices = 0;
if(!waveformEnabled.checked || audioBuffers[checkForVoices] == null) {
//trace('Epic fail on the waveform lol');
return;
}
var sampleMult:Float = audioBuffers[checkForVoices].sampleRate / 44100;
var index:Int = Std.int(sectionStartTime() * 44.0875 * sampleMult);
var drawIndex:Int = 0;
var steps:Int = _song.notes[curSection].lengthInSteps;
if(Math.isNaN(steps) || steps < 1) steps = 16;
var samplesPerRow:Int = Std.int(((Conductor.stepCrochet * steps * 1.1 * sampleMult) / 16) / zoomList[curZoom]);
if(samplesPerRow < 1) samplesPerRow = 1;
var waveBytes:Bytes = audioBuffers[checkForVoices].data.toBytes();
var min:Float = 0;
var max:Float = 0;
while (index < (waveBytes.length - 1))
{
var byte:Int = waveBytes.getUInt16(index * 4);
if (byte > 65535 / 2)
byte -= 65535;
var sample:Float = (byte / 65535);
if (sample > 0)
{
if (sample > max)
max = sample;
}
else if (sample < 0)
{
if (sample < min)
min = sample;
}
if ((index % samplesPerRow) == 0)
{
// trace("min: " + min + ", max: " + max);
/*if (drawIndex > gridBG.height)
{
drawIndex = 0;
}*/
var pixelsMin:Float = Math.abs(min * (GRID_SIZE * 8));
var pixelsMax:Float = max * (GRID_SIZE * 8);
waveformSprite.pixels.fillRect(new Rectangle(Std.int((GRID_SIZE * 4) - pixelsMin), drawIndex, pixelsMin + pixelsMax, 1), FlxColor.BLUE);
drawIndex++;
min = 0;
max = 0;
if(drawIndex > gridBG.height) break;
}
index++;
}
waveformPrinted = true;
#end
}
function changeNoteSustain(value:Float):Void
{
if (curSelectedNote != null)
{
if (curSelectedNote[2] != null)
{
curSelectedNote[2] += value;
curSelectedNote[2] = Math.max(curSelectedNote[2], 0);
}
}
updateNoteUI();
updateGrid();
}
function recalculateSteps(add:Float = 0):Int
{
var lastChange:BPMChangeEvent = {
stepTime: 0,
songTime: 0,
bpm: 0
}
for (i in 0...Conductor.bpmChangeMap.length)
{
if (FlxG.sound.music.time > Conductor.bpmChangeMap[i].songTime)
lastChange = Conductor.bpmChangeMap[i];
}
curStep = lastChange.stepTime + Math.floor((FlxG.sound.music.time - lastChange.songTime + add) / Conductor.stepCrochet);
updateBeat();
return curStep;
}
function resetSection(songBeginning:Bool = false):Void
{
updateGrid();
FlxG.sound.music.pause();
// Basically old shit from changeSection???
FlxG.sound.music.time = sectionStartTime();
if (songBeginning)
{
FlxG.sound.music.time = 0;
curSection = 0;
}
if(vocals != null) {
vocals.pause();
vocals.time = FlxG.sound.music.time;
}
updateCurStep();
updateGrid();
updateSectionUI();
updateWaveform();
}
function changeSection(sec:Int = 0, ?updateMusic:Bool = true):Void
{
trace('changing section' + sec);
if (_song.notes[sec] != null)
{
curSection = sec;
updateGrid();
if (updateMusic)
{
FlxG.sound.music.pause();
/*var daNum:Int = 0;
var daLength:Float = 0;
while (daNum <= sec)
{
daLength += lengthBpmBullshit();
daNum++;
}*/
FlxG.sound.music.time = sectionStartTime();
if(vocals != null) {
vocals.pause();
vocals.time = FlxG.sound.music.time;
}
updateCurStep();
}
updateGrid();
updateSectionUI();
}
else
{
changeSection();
}
Conductor.songPosition = FlxG.sound.music.time;
updateWaveform();
}
function updateSectionUI():Void
{
var sec = _song.notes[curSection];
stepperLength.value = sec.lengthInSteps;
check_mustHitSection.checked = sec.mustHitSection;
check_altAnim.checked = sec.altAnim;
check_changeBPM.checked = sec.changeBPM;
stepperSectionBPM.value = sec.bpm;
updateHeads();
}
function updateHeads():Void
{
var healthIconP1:String = loadHealthIconFromCharacter(_song.player1);
var healthIconP2:String = loadHealthIconFromCharacter(_song.player2);
if (_song.notes[curSection].mustHitSection)
{
leftIcon.changeIcon(healthIconP1);
rightIcon.changeIcon(healthIconP2);
}
else
{
leftIcon.changeIcon(healthIconP2);
rightIcon.changeIcon(healthIconP1);
}
}
function loadHealthIconFromCharacter(char:String) {
var characterPath:String = 'characters/' + char + '.json';
#if MODS_ALLOWED
var path:String = Paths.modFolders(characterPath);
if (!FileSystem.exists(path)) {
path = Paths.getPreloadPath(characterPath);
}
if (!FileSystem.exists(path))
#else
var path:String = Paths.getPreloadPath(characterPath);
if (!OpenFlAssets.exists(path))
#end
{
path = Paths.getPreloadPath('characters/' + Character.DEFAULT_CHARACTER + '.json'); //If a character couldn't be found, change him to BF just to prevent a crash
}
#if MODS_ALLOWED
var rawJson = File.getContent(path);
#else
var rawJson = OpenFlAssets.getText(path);
#end
var json:Character.CharacterFile = cast Json.parse(rawJson);
return json.healthicon;
}
function updateNoteUI():Void
{
if (curSelectedNote != null) {
if(curSelectedNote[1] > -1) {
stepperSusLength.value = curSelectedNote[2];
if(curSelectedNote[3] != null) {
currentType = noteTypeMap.get(curSelectedNote[3]);
if(currentType <= 0) {
noteTypeDropDown.selectedLabel = '';
} else {
noteTypeDropDown.selectedLabel = currentType + '. ' + curSelectedNote[3];
}
}
} else {
eventDropDown.selectedLabel = curSelectedNote[2];
var selected:Int = Std.parseInt(eventDropDown.selectedId);
if(selected > 0 && selected < eventStuff.length) {
descText.text = eventStuff[selected][1];
}
value1InputText.text = curSelectedNote[3];
value2InputText.text = curSelectedNote[4];
}
strumTimeInputText.text = '' + curSelectedNote[0];
}
}
function updateGrid():Void
{
curRenderedNotes.clear();
curRenderedSustains.clear();
curRenderedNoteType.clear();
nextRenderedNotes.clear();
nextRenderedSustains.clear();
if (_song.notes[curSection].changeBPM && _song.notes[curSection].bpm > 0)
{
Conductor.changeBPM(_song.notes[curSection].bpm);
trace('BPM of this section:');
}
else
{
// get last bpm
var daBPM:Float = _song.bpm;
for (i in 0...curSection)
if (_song.notes[i].changeBPM)
daBPM = _song.notes[i].bpm;
Conductor.changeBPM(daBPM);
}
/* // PORT BULLSHIT, INCASE THERE'S NO SUSTAIN DATA FOR A NOTE
for (sec in 0..._song.notes.length)
{
for (notesse in 0..._song.notes[sec].sectionNotes.length)
{
if (_song.notes[sec].sectionNotes[notesse][2] == null)
{
trace('SUS NULL');
_song.notes[sec].sectionNotes[notesse][2] = 0;
}
}
}
*/
// CURRENT SECTION
for (i in _song.notes[curSection].sectionNotes)
{
var note:Note = setupNoteData(i, false);
curRenderedNotes.add(note);
if (note.sustainLength > 0)
{
curRenderedSustains.add(setupSusNote(note));
}
if(note.y < -150) note.y = -150;
if(note.noteData < 0) {
var daText:AttachedFlxText = new AttachedFlxText(0, 0, 400, 'Event: ' + note.eventName + ' (' + Math.floor(note.strumTime) + ' ms)' + '\nValue 1: ' + note.eventVal1 + '\nValue 2: ' + note.eventVal2, 12);
daText.setFormat(Paths.font("vcr.ttf"), 12, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
daText.xAdd = -410;
daText.borderSize = 1;
curRenderedNoteType.add(daText);
daText.sprTracker = note;
} else {
if(i[3] != null && note.noteType != null && note.noteType.length > 0) {
var typeInt:Null<Int> = noteTypeMap.get(i[3]);
var theType:String = '' + typeInt;
if(typeInt == null) theType = '?';
var daText:AttachedFlxText = new AttachedFlxText(0, 0, 100, theType, 24);
daText.setFormat(Paths.font("vcr.ttf"), 24, FlxColor.WHITE, CENTER, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
daText.xAdd = -32;
daText.yAdd = 6;
daText.borderSize = 1;
curRenderedNoteType.add(daText);
daText.sprTracker = note;
}
note.mustPress = _song.notes[curSection].mustHitSection;
if(i[1] > 3) note.mustPress = !note.mustPress;
}
}
// NEXT SECTION
if(curSection < _song.notes.length-1) {
for (i in _song.notes[curSection+1].sectionNotes)
{
var note:Note = setupNoteData(i, true);
note.alpha = 0.6;
nextRenderedNotes.add(note);
if (note.sustainLength > 0)
{
nextRenderedSustains.add(setupSusNote(note));
}
}
}
}
function setupNoteData(i:Array<Dynamic>, isNextSection:Bool):Note
{
var daNoteInfo = i[1];
var daStrumTime = i[0];
var daSus:Dynamic = i[2];
var note:Note = new Note(daStrumTime, daNoteInfo % 4, null, null, true);
if(daNoteInfo > -1) { //Common note
if(!Std.isOfType(i[3], String)) //Convert old note type to new note type format
{
i[3] = noteTypeIntMap.get(i[3]);
}
if(i.length > 3 && (i[3] == null || i[3].length < 1))
{
i.remove(i[3]);
}
note.sustainLength = daSus;
note.noteType = i[3];
} else { //Event note
note.loadGraphic(Paths.image('eventArrow'));
note.eventName = daSus;
note.eventVal1 = i[3];
note.eventVal2 = i[4];
}
note.setGraphicSize(GRID_SIZE, GRID_SIZE);
note.updateHitbox();
note.x = Math.floor(daNoteInfo * GRID_SIZE) + GRID_SIZE;
if(isNextSection && _song.notes[curSection].mustHitSection != _song.notes[curSection+1].mustHitSection) {
if(daNoteInfo > 3) {
note.x -= GRID_SIZE * 4;
} else if(daNoteInfo > -1) {
note.x += GRID_SIZE * 4;
}
}
note.y = (GRID_SIZE * (isNextSection ? 16 : 0)) * zoomList[curZoom] + Math.floor(getYfromStrum((daStrumTime - sectionStartTime(isNextSection ? 1 : 0)) % (Conductor.stepCrochet * _song.notes[curSection].lengthInSteps), false));
return note;
}
function setupSusNote(note:Note):FlxSprite {
var height:Int = Math.floor(FlxMath.remapToRange(note.sustainLength, 0, Conductor.stepCrochet * 16, 0, (gridBG.height / gridMult)) + (GRID_SIZE * zoomList[curZoom]) - GRID_SIZE / 2);
var minHeight:Int = Std.int((GRID_SIZE * zoomList[curZoom] / 2) + GRID_SIZE / 2);
if(height < minHeight) height = minHeight;
if(height < 1) height = 1; //Prevents error of invalid height
var spr:FlxSprite = new FlxSprite(note.x + (GRID_SIZE * 0.5) - 4, note.y + GRID_SIZE / 2).makeGraphic(8, height);
return spr;
}
private function addSection(lengthInSteps:Int = 16):Void
{
var sec:SwagSection = {
lengthInSteps: lengthInSteps,
bpm: _song.bpm,
changeBPM: false,
mustHitSection: true,
sectionNotes: [],
typeOfSection: 0,
altAnim: false
};
_song.notes.push(sec);
}
function selectNote(note:Note):Void
{
var noteDataToCheck:Int = note.noteData;
if(noteDataToCheck > -1 && note.mustPress != _song.notes[curSection].mustHitSection) noteDataToCheck += 4;
for (i in _song.notes[curSection].sectionNotes)
{
if (i != curSelectedNote && i.length > 2 && i[0] == note.strumTime && i[1] == noteDataToCheck)
{
curSelectedNote = i;
break;
}
}
updateGrid();
updateNoteUI();
}
function deleteNote(note:Note):Void
{
var noteDataToCheck:Int = note.noteData;
if(noteDataToCheck > -1 && note.mustPress != _song.notes[curSection].mustHitSection) noteDataToCheck += 4;
for (i in _song.notes[curSection].sectionNotes)
{
if (i[0] == note.strumTime && i[1] == noteDataToCheck)
{
if(i == curSelectedNote) curSelectedNote = null;
FlxG.log.add('FOUND EVIL NUMBER');
_song.notes[curSection].sectionNotes.remove(i);
break;
}
}
updateGrid();
}
function clearSong():Void
{
for (daSection in 0..._song.notes.length)
{
_song.notes[daSection].sectionNotes = [];
}
updateGrid();
}
private function addNote():Void
{
var noteStrum = getStrumTime(dummyArrow.y, false) + sectionStartTime();
var noteData = Math.floor((FlxG.mouse.x - GRID_SIZE) / GRID_SIZE);
var noteSus = 0;
var daAlt = false;
var daType = currentType;
if(noteData > -1) {
_song.notes[curSection].sectionNotes.push([noteStrum, noteData, noteSus, noteTypeIntMap.get(daType)]);
} else {
var event = eventStuff[Std.parseInt(eventDropDown.selectedId)][0];
var text1 = value1InputText.text;
var text2 = value2InputText.text;
_song.notes[curSection].sectionNotes.push([noteStrum, noteData, event, text1, text2]);
}
curSelectedNote = _song.notes[curSection].sectionNotes[_song.notes[curSection].sectionNotes.length - 1];
if (FlxG.keys.pressed.CONTROL && noteData > -1)
{
_song.notes[curSection].sectionNotes.push([noteStrum, (noteData + 4) % 8, noteSus, noteTypeIntMap.get(daType)]);
}
trace(noteData + ', ' + noteStrum + ', ' + curSection);
strumTimeInputText.text = '' + curSelectedNote[0];
updateGrid();
updateNoteUI();
}
function getStrumTime(yPos:Float, doZoomCalc:Bool = true):Float
{
var leZoom:Float = zoomList[curZoom];
if(!doZoomCalc) leZoom = 1;
return FlxMath.remapToRange(yPos, gridBG.y, gridBG.y + (gridBG.height / gridMult) * leZoom, 0, 16 * Conductor.stepCrochet);
}
function getYfromStrum(strumTime:Float, doZoomCalc:Bool = true):Float
{
var leZoom:Float = zoomList[curZoom];
if(!doZoomCalc) leZoom = 1;
return FlxMath.remapToRange(strumTime, 0, 16 * Conductor.stepCrochet, gridBG.y, gridBG.y + (gridBG.height / gridMult) * leZoom);
}
/*
function calculateSectionLengths(?sec:SwagSection):Int
{
var daLength:Int = 0;
for (i in _song.notes)
{
var swagLength = i.lengthInSteps;
if (i.typeOfSection == Section.COPYCAT)
swagLength * 2;
daLength += swagLength;
if (sec != null && sec == i)
{
trace('swag loop??');
break;
}
}
return daLength;
}*/
private var daSpacing:Float = 0.3;
function loadLevel():Void
{
trace(_song.notes);
}
function getNotes():Array<Dynamic>
{
var noteData:Array<Dynamic> = [];
for (i in _song.notes)
{
noteData.push(i.sectionNotes);
}
return noteData;
}
function loadJson(song:String):Void
{
PlayState.SONG = Song.loadFromJson(song.toLowerCase(), song.toLowerCase());
MusicBeatState.resetState();
}
function autosaveSong():Void
{
FlxG.save.data.autosave = Json.stringify({
"song": _song
});
FlxG.save.flush();
}
function clearEvents() {
for (sec in 0..._song.notes.length) {
var count:Int = 0;
while(count < _song.notes[sec].sectionNotes.length) {
var note:Array<Dynamic> = _song.notes[sec].sectionNotes[count];
if(note != null && note[1] < 0) {
_song.notes[sec].sectionNotes.remove(note);
} else {
count++;
}
}
}
updateGrid();
}
private function saveLevel()
{
var json = {
"song": _song
};
var data:String = Json.stringify(json, "\t");
if ((data != null) && (data.length > 0))
{
_file = new FileReference();
_file.addEventListener(Event.COMPLETE, onSaveComplete);
_file.addEventListener(Event.CANCEL, onSaveCancel);
_file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file.save(data.trim(), Paths.formatToSongPath(_song.song) + ".json");
}
}
private function saveEvents()
{
var events:Array<SwagSection> = [];
for (sec in 0..._song.notes.length) {
if(_song.notes[sec] == null) continue;
var arrayNotes:Array<Dynamic> = [];
for (i in 0..._song.notes[sec].sectionNotes.length) {
var note:Array<Dynamic> = _song.notes[sec].sectionNotes[i];
if(note != null && note[1] < 0) {
arrayNotes.push(note);
}
}
var sex:SwagSection = {
sectionNotes: arrayNotes,
lengthInSteps: 16,
typeOfSection: 0,
mustHitSection: false,
bpm: 0,
changeBPM: false,
altAnim: false
};
events.push(sex);
}
var eventsSong:SwagSong = {
song: _song.song,
notes: events,
bpm: _song.bpm,
needsVoices: _song.needsVoices,
speed: _song.speed,
arrowSkin: _song.arrowSkin,
splashSkin: _song.splashSkin,
player1: _song.player1,
player2: _song.player2,
player3: _song.player3,
stage: _song.stage,
validScore: false
};
var json = {
"song": eventsSong
}
var data:String = Json.stringify(json, "\t");
if ((data != null) && (data.length > 0))
{
_file = new FileReference();
_file.addEventListener(Event.COMPLETE, onSaveComplete);
_file.addEventListener(Event.CANCEL, onSaveCancel);
_file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file.save(data.trim(), "events.json");
}
}
function onSaveComplete(_):Void
{
_file.removeEventListener(Event.COMPLETE, onSaveComplete);
_file.removeEventListener(Event.CANCEL, onSaveCancel);
_file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file = null;
FlxG.log.notice("Successfully saved LEVEL DATA.");
}
/**
* Called when the save file dialog is cancelled.
*/
function onSaveCancel(_):Void
{
_file.removeEventListener(Event.COMPLETE, onSaveComplete);
_file.removeEventListener(Event.CANCEL, onSaveCancel);
_file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file = null;
}
/**
* Called if there is an error while saving the gameplay recording.
*/
function onSaveError(_):Void
{
_file.removeEventListener(Event.COMPLETE, onSaveComplete);
_file.removeEventListener(Event.CANCEL, onSaveCancel);
_file.removeEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file = null;
FlxG.log.error("Problem saving Level data");
}
}
class AttachedFlxText extends FlxText
{
public var sprTracker:FlxSprite;
public var xAdd:Float = 0;
public var yAdd:Float = 0;
public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, Size:Int = 8, EmbeddedFont:Bool = true) {
super(X, Y, FieldWidth, Text, Size, EmbeddedFont);
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (sprTracker != null) {
setPosition(sprTracker.x + xAdd, sprTracker.y + yAdd);
angle = sprTracker.angle;
alpha = sprTracker.alpha;
}
}
}