Merge branch 'Time-Signature-Changes' into new-conductor
# Conflicts: # .gitignore # source/funkin/backend/FunkinSprite.hx # source/funkin/backend/chart/ChartData.hx # source/funkin/backend/chart/EventsData.hx # source/funkin/backend/system/Conductor.hx # source/funkin/backend/utils/CoolUtil.hx # source/funkin/editors/charter/Charter.hx # source/funkin/editors/charter/CharterEvent.hx # source/funkin/editors/charter/CharterEventScreen.hx # source/funkin/editors/charter/CharterMetaDataScreen.hx # source/funkin/editors/charter/SongCreationScreen.hx # source/funkin/game/PlayState.hx
This commit is contained in:
@@ -613,6 +613,8 @@ class Charter extends UIState {
|
||||
gridBackdrops.bottomLimitY = __endStep * 40;
|
||||
eventsBackdrop.bottomSeparator.y = gridBackdrops.bottomLimitY-2;
|
||||
|
||||
CharterGridSeperatorBase.lastConductorSprY = Math.NEGATIVE_INFINITY;
|
||||
|
||||
updateWaveforms();
|
||||
}
|
||||
|
||||
@@ -846,6 +848,7 @@ class Charter extends UIState {
|
||||
s.cursor = BUTTON;
|
||||
}
|
||||
}
|
||||
checkSelectionForBPMUpdates();
|
||||
if (!(verticalChange == 0 && horizontalChange == 0)) {
|
||||
notesGroup.sortNotes(); eventsGroup.sortEvents();
|
||||
undos.addToUndo(CSelectionDrag(undoDrags));
|
||||
@@ -1037,11 +1040,7 @@ class Charter extends UIState {
|
||||
notesGroup.sortNotes();
|
||||
notesGroup.autoSort = true;
|
||||
|
||||
for (s in selection)
|
||||
if (s is CharterEvent) {
|
||||
Charter.instance.updateBPMEvents();
|
||||
break;
|
||||
}
|
||||
checkSelectionForBPMUpdates();
|
||||
|
||||
if (addToUndo)
|
||||
undos.addToUndo(CCreateSelection(selection));
|
||||
@@ -1065,11 +1064,7 @@ class Charter extends UIState {
|
||||
notesGroup.sortNotes();
|
||||
notesGroup.autoSort = true;
|
||||
|
||||
for (s in selection)
|
||||
if (s is CharterEvent) {
|
||||
Charter.instance.updateBPMEvents();
|
||||
break;
|
||||
}
|
||||
checkSelectionForBPMUpdates();
|
||||
|
||||
if (addToUndo)
|
||||
undos.addToUndo(CDeleteSelection(selection));
|
||||
@@ -1256,12 +1251,13 @@ class Charter extends UIState {
|
||||
for (strumLine in strumLines.members) strumLine.vocals.pause();
|
||||
}
|
||||
|
||||
songPosInfo.text = '${CoolUtil.timeToStr(Conductor.songPosition)} / ${CoolUtil.timeToStr(songLength)}'
|
||||
+ '\nStep: ${curStep}'
|
||||
+ '\nBeat: ${curBeat}'
|
||||
+ '\nMeasure: ${curMeasure}'
|
||||
+ '\nBPM: ${Conductor.bpm}'
|
||||
+ '\nTime Signature: ${Conductor.beatsPerMeasure}/${Conductor.stepsPerBeat}';
|
||||
var curChange = Conductor.curChange;
|
||||
songPosInfo.text = '${CoolUtil.timeToStr(songPos)} / ${CoolUtil.timeToStr(songLength)}'
|
||||
+ '\nStep: $curStep'
|
||||
+ '\nBeat: $curBeat'
|
||||
+ '\nMeasure: $curMeasure'
|
||||
+ '\nBPM: ${(curChange != null && curChange.continuous && curChange.endSongTime > songPos) ? FlxMath.roundDecimal(Conductor.bpm, 3) : Conductor.bpm}'
|
||||
+ '\nTime Signature: ${Conductor.beatsPerMeasure}/${Conductor.denominator}';
|
||||
|
||||
if (charterCamera.zoom != (charterCamera.zoom = lerp(charterCamera.zoom, __camZoom, __firstFrame ? 1 : 0.125)))
|
||||
updateDisplaySprites();
|
||||
@@ -1441,6 +1437,8 @@ class Charter extends UIState {
|
||||
selection = sObjects;
|
||||
_edit_copy(_); // to fix stupid bugs
|
||||
|
||||
checkSelectionForBPMUpdates();
|
||||
|
||||
undos.addToUndo(CCreateSelection(sObjects.copy()));
|
||||
}
|
||||
|
||||
@@ -1486,6 +1484,7 @@ class Charter extends UIState {
|
||||
if (s.selectable.draggable) s.selectable.handleDrag(s.change * -1);
|
||||
|
||||
selection = [for (s in selectionDrags) s.selectable];
|
||||
Charter.instance.updateBPMEvents();
|
||||
case CEditSustains(changes):
|
||||
for(n in changes)
|
||||
n.note.updatePos(n.note.step, n.note.id, n.before, n.note.type);
|
||||
@@ -1531,6 +1530,7 @@ class Charter extends UIState {
|
||||
for (s in selectionDrags)
|
||||
if (s.selectable.draggable) s.selectable.handleDrag(s.change);
|
||||
//this.selection = selection;
|
||||
Charter.instance.updateBPMEvents();
|
||||
case CEditSustains(changes):
|
||||
for(n in changes)
|
||||
n.note.updatePos(n.note.step, n.note.id, n.after, n.note.type);
|
||||
@@ -1643,11 +1643,9 @@ class Charter extends UIState {
|
||||
}
|
||||
function _view_showeventSecSeparator(t) {
|
||||
t.icon = (Options.charterShowSections = !Options.charterShowSections) ? 1 : 0;
|
||||
eventsBackdrop.eventSecSeparator.visible = gridBackdrops.sectionsVisible = Options.charterShowSections;
|
||||
}
|
||||
function _view_showeventBeatSeparator(t) {
|
||||
t.icon = (Options.charterShowBeats = !Options.charterShowBeats) ? 1 : 0;
|
||||
eventsBackdrop.eventBeatSeparator.visible = gridBackdrops.beatsVisible = Options.charterShowBeats;
|
||||
}
|
||||
function _view_switchWaveformDetail(t) {
|
||||
t.icon = (Options.charterLowDetailWaveforms = !Options.charterLowDetailWaveforms) ? 1 : 0;
|
||||
@@ -1847,14 +1845,30 @@ class Charter extends UIState {
|
||||
}
|
||||
|
||||
public function updateBPMEvents() {
|
||||
eventsGroup.sortEvents();
|
||||
Conductor.mapCharterBPMChanges(PlayState.SONG);
|
||||
buildEvents();
|
||||
|
||||
Conductor.mapBPMChanges(PlayState.SONG);
|
||||
Conductor.changeBPM(PlayState.SONG.meta.bpm, cast PlayState.SONG.meta.beatsPerMeasure.getDefault(4), cast PlayState.SONG.meta.stepsPerBeat.getDefault(4));
|
||||
|
||||
for(e in eventsGroup.members) {
|
||||
for(event in e.events) {
|
||||
if (event.name == "BPM Change" || event.name == "Time Signature Change" || event.name == "Continuous BPM Change") {
|
||||
e.refreshEventIcons();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refreshBPMSensitive();
|
||||
}
|
||||
|
||||
public inline function checkSelectionForBPMUpdates() {
|
||||
for (s in selection)
|
||||
if (s is CharterEvent) {
|
||||
Charter.instance.updateBPMEvents();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public inline function hitsoundsEnabled(id:Int)
|
||||
return strumLines.members[id] != null && strumLines.members[id].hitsounds;
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
|
||||
|
||||
public var conductorSprY:Float = 0;
|
||||
public var bottomLimitY:Float = 0;
|
||||
public var sectionsVisible:Bool = true;
|
||||
public var beatsVisible:Bool = true;
|
||||
|
||||
// Just here so you can update display sprites all dat and above
|
||||
public var strumlinesAmount:Int = 0;
|
||||
@@ -61,8 +59,6 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
|
||||
|
||||
grid.conductorFollowerSpr.y = conductorSprY;
|
||||
grid.bottomSeparator.y = (grid.bottomLimit.y = bottomLimitY)-2;
|
||||
grid.sectionSeparator.visible = sectionsVisible;
|
||||
grid.beatSeparator.visible = beatsVisible;
|
||||
|
||||
grid.waveformSprite.shader = strumLine.waveformShader;
|
||||
|
||||
@@ -119,8 +115,7 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
public var waveformSprite:FlxSprite;
|
||||
|
||||
public var conductorFollowerSpr:FlxSprite;
|
||||
public var beatSeparator:FlxBackdrop;
|
||||
public var sectionSeparator:FlxBackdrop;
|
||||
public var beatSeparator:CharterGridSeperator;
|
||||
|
||||
public var notesGroup:FlxTypedGroup<CharterNote> = new FlxTypedGroup<CharterNote>();
|
||||
public var strumLine:CharterStrumline;
|
||||
@@ -136,23 +131,14 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
waveformSprite.updateHitbox();
|
||||
add(waveformSprite);
|
||||
|
||||
sectionSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
sectionSeparator.y = -2;
|
||||
sectionSeparator.visible = Options.charterShowSections;
|
||||
|
||||
beatSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
beatSeparator.y = -1;
|
||||
beatSeparator.visible = Options.charterShowBeats;
|
||||
|
||||
for(sep in [sectionSeparator, beatSeparator]) {
|
||||
sep.makeSolid(1, 1, -1);
|
||||
sep.alpha = 0.5;
|
||||
sep.scrollFactor.set(1, 1);
|
||||
sep.scale.set((4 * 40), sep == sectionSeparator ? 4 : 2);
|
||||
sep.updateHitbox();
|
||||
}
|
||||
beatSeparator = new CharterGridSeperator();
|
||||
beatSeparator.makeSolid(1, 1, -1);
|
||||
beatSeparator.alpha = 0.5;
|
||||
beatSeparator.scrollFactor.set(1, 1);
|
||||
beatSeparator.scale.set((4 * 40), 2);
|
||||
beatSeparator.updateHitbox();
|
||||
add(beatSeparator);
|
||||
add(sectionSeparator);
|
||||
|
||||
add(notesGroup);
|
||||
|
||||
bottomSeparator = new FlxSprite(0,-2);
|
||||
@@ -200,15 +186,12 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
alpha = strumLine.strumLine.visible ? 0.9 : 0.4;
|
||||
} else alpha = 0.9;
|
||||
|
||||
for (spr in [gridBackDrop, sectionSeparator, beatSeparator, topLimit, bottomLimit,
|
||||
for (spr in [gridBackDrop, beatSeparator, topLimit, bottomLimit,
|
||||
topSeparator, bottomSeparator, conductorFollowerSpr, waveformSprite]) {
|
||||
spr.x = x; if (spr != waveformSprite) spr.alpha = alpha;
|
||||
spr.cameras = this.cameras;
|
||||
}
|
||||
|
||||
sectionSeparator.spacing.y = (10 * Conductor.beatsPerMeasure * Conductor.stepsPerBeat) - 1;
|
||||
beatSeparator.spacing.y = (20 * Conductor.stepsPerBeat) - 1;
|
||||
|
||||
topLimit.scale.set(4 * 40, Math.ceil(FlxG.height / cameras[0].zoom));
|
||||
topLimit.updateHitbox();
|
||||
topLimit.y = -topLimit.height;
|
||||
@@ -237,6 +220,159 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
}
|
||||
}
|
||||
|
||||
class CharterGridSeperatorBase extends FlxSprite {
|
||||
|
||||
private static var minStep:Float = 0;
|
||||
private static var maxStep:Float = 0;
|
||||
|
||||
private static var minBeat:Float = 0;
|
||||
private static var maxBeat:Float = 0;
|
||||
|
||||
private static var minMeasure:Float = 0;
|
||||
private static var maxMeasure:Float = 0;
|
||||
|
||||
private static var lastMinBeat:Float = -1;
|
||||
private static var lastMaxBeat:Float = -1;
|
||||
|
||||
private static var lastMinMeasure:Float = -1;
|
||||
private static var lastMaxMeasure:Float = -1;
|
||||
|
||||
public static var lastConductorSprY:Float = Math.NEGATIVE_INFINITY;
|
||||
|
||||
private static var beatStepTimes:Array<Float> = [];
|
||||
private static var measureStepTimes:Array<Float> = [];
|
||||
private static var timeSignatureChangeGaps:Array<Float> = [];
|
||||
|
||||
private function recalculateBeats() {
|
||||
var conductorSprY = Charter.instance.gridBackdrops.conductorSprY;
|
||||
if (conductorSprY == lastConductorSprY) return;
|
||||
|
||||
var zoomOffset = ((FlxG.height * (1/cameras[0].zoom)) * 0.5);
|
||||
|
||||
minStep = (conductorSprY - zoomOffset)/40;
|
||||
maxStep = (conductorSprY + zoomOffset)/40;
|
||||
|
||||
var minTime:Float = Conductor.getStepsInTime(minStep);
|
||||
var maxTime:Float = Conductor.getStepsInTime(maxStep);
|
||||
|
||||
var minBpmChange = Conductor.bpmChangeMap[Conductor.getTimeInChangeIndex(minTime)];
|
||||
var maxBpmChange = Conductor.bpmChangeMap[Conductor.getTimeInChangeIndex(maxTime)];
|
||||
|
||||
minBeat = Conductor.getTimeInBeats(minTime);
|
||||
maxBeat = Conductor.getTimeInBeats(maxTime);
|
||||
|
||||
minMeasure = minBpmChange.measureTime + (minBeat - minBpmChange.beatTime) / minBpmChange.beatsPerMeasure;
|
||||
maxMeasure = maxBpmChange.measureTime + (maxBeat - maxBpmChange.beatTime) / maxBpmChange.beatsPerMeasure;
|
||||
|
||||
//cap out the beats/measures at the end of the song
|
||||
var endTime = Conductor.getStepsInTime(Charter.instance.__endStep);
|
||||
var endBeat = Conductor.getTimeInBeats(endTime);
|
||||
var endBpmChange = Conductor.bpmChangeMap[Conductor.getTimeInChangeIndex(endTime)];
|
||||
var endMeasure = endBpmChange.measureTime + (endBeat - endBpmChange.beatTime) / endBpmChange.beatsPerMeasure;
|
||||
|
||||
if (maxBeat > endBeat) maxBeat = endBeat;
|
||||
if (maxMeasure > endMeasure) maxMeasure = endMeasure;
|
||||
if (minMeasure < 0) minMeasure = 0;
|
||||
if (minBeat < 0) minBeat = 0;
|
||||
|
||||
//only calculate if needed
|
||||
if ((minBeat != lastMinBeat) || (maxBeat != lastMaxBeat) || (minMeasure != lastMinMeasure) || (maxMeasure != lastMaxMeasure) || lastConductorSprY == Math.NEGATIVE_INFINITY) {
|
||||
calculateTimeSignatureGaps();
|
||||
calculateStepTimes();
|
||||
lastMinBeat = minBeat;
|
||||
lastMaxBeat = maxBeat;
|
||||
lastMinMeasure = minMeasure;
|
||||
lastMaxMeasure = maxMeasure;
|
||||
}
|
||||
|
||||
lastConductorSprY = conductorSprY;
|
||||
}
|
||||
|
||||
private inline function calculateTimeSignatureGaps() {
|
||||
//for time signatures that start mid step
|
||||
timeSignatureChangeGaps.splice(0, timeSignatureChangeGaps.length);
|
||||
for (i => change in Conductor.bpmChangeMap) {
|
||||
if (change.stepTime >= minStep && change.stepTime <= maxStep) {
|
||||
//get step while ignoring the current change
|
||||
var index:Int = CoolUtil.boundInt(i-1, 0, Conductor.bpmChangeMap.length - 1);
|
||||
var step:Float = Conductor.getTimeWithBPMInSteps(change.songTime, index, Conductor.getTimeWithIndexInBPM(change.songTime, index));
|
||||
|
||||
if (Math.ceil(step) - step > 0 && (step - Math.floor(step)) > FlxMath.EPSILON) { //mid step change
|
||||
timeSignatureChangeGaps.push(step);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline function calculateStepTimes() {
|
||||
beatStepTimes.splice(0, beatStepTimes.length);
|
||||
for (i in Math.floor(minBeat)...Math.ceil(maxBeat)) {
|
||||
beatStepTimes.push(Conductor.getTimeInSteps(Conductor.getBeatsInTime(i)));
|
||||
}
|
||||
measureStepTimes.splice(0, measureStepTimes.length);
|
||||
for (i in Math.floor(minMeasure)...Math.ceil(maxMeasure)) {
|
||||
measureStepTimes.push(Conductor.getTimeInSteps(Conductor.getMeasuresInTime(i)));
|
||||
}
|
||||
}
|
||||
|
||||
override public function draw() {
|
||||
|
||||
//should only need to recalculate once per frame and will be shared across each instance
|
||||
recalculateBeats();
|
||||
|
||||
drawTimeSignatureChangeGaps();
|
||||
|
||||
if (Options.charterShowBeats) drawBeats();
|
||||
if (Options.charterShowSections) drawMeasures();
|
||||
}
|
||||
|
||||
private function drawBeats(offset:Float = 0.0) {
|
||||
for (i in beatStepTimes) {
|
||||
y = (i*40)+offset;
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
private function drawMeasures(offset:Float = 0.0) {
|
||||
for (i in measureStepTimes) {
|
||||
y = (i*40)+offset;
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
private function drawTimeSignatureChangeGaps() {
|
||||
if (timeSignatureChangeGaps.length == 0) return;
|
||||
var prevColor = color;
|
||||
var prevBlend = blend;
|
||||
|
||||
color = 0xFF888888;
|
||||
blend = MULTIPLY;
|
||||
|
||||
for (step in timeSignatureChangeGaps) {
|
||||
y = step*40;
|
||||
var diff = Math.ceil(step) - step;
|
||||
scale.y = diff*40;
|
||||
updateHitbox();
|
||||
|
||||
super.draw();
|
||||
}
|
||||
|
||||
color = prevColor;
|
||||
blend = prevBlend;
|
||||
}
|
||||
}
|
||||
|
||||
class CharterGridSeperator extends CharterGridSeperatorBase {
|
||||
override private function drawBeats(offset:Float = 0.0) {
|
||||
scale.y = 2;
|
||||
updateHitbox();
|
||||
super.drawBeats(-2);
|
||||
}
|
||||
override private function drawMeasures(offset:Float = 0.0) {
|
||||
scale.y = 4;
|
||||
updateHitbox();
|
||||
super.drawMeasures(-3);
|
||||
}
|
||||
}
|
||||
|
||||
class CharterBackdropDummy extends UISprite {
|
||||
var parent:CharterBackdropGroup;
|
||||
public function new(parent:CharterBackdropGroup) {
|
||||
@@ -258,8 +394,7 @@ class CharterBackdropDummy extends UISprite {
|
||||
}
|
||||
|
||||
class EventBackdrop extends FlxBackdrop {
|
||||
public var eventBeatSeparator:FlxBackdrop;
|
||||
public var eventSecSeparator:FlxBackdrop;
|
||||
public var eventBeatSeparator:CharterEventGridSeperator;
|
||||
|
||||
public var topSeparator:FlxSprite;
|
||||
public var bottomSeparator:FlxSprite;
|
||||
@@ -269,25 +404,10 @@ class EventBackdrop extends FlxBackdrop {
|
||||
alpha = 0.9;
|
||||
|
||||
// Separators
|
||||
eventSecSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
eventSecSeparator.y = -2;
|
||||
eventSecSeparator.visible = Options.charterShowSections;
|
||||
|
||||
eventBeatSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
eventBeatSeparator.y = -1;
|
||||
eventBeatSeparator.visible = Options.charterShowBeats;
|
||||
|
||||
for(sep in [eventSecSeparator, eventBeatSeparator]) {
|
||||
sep.makeSolid(1, 1, -1);
|
||||
sep.alpha = 0.5;
|
||||
sep.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
eventSecSeparator.scale.set(20, 4);
|
||||
eventSecSeparator.updateHitbox();
|
||||
|
||||
eventBeatSeparator.scale.set(10, 2);
|
||||
eventBeatSeparator.updateHitbox();
|
||||
eventBeatSeparator = new CharterEventGridSeperator();
|
||||
eventBeatSeparator.makeSolid(1, 1, -1);
|
||||
eventBeatSeparator.alpha = 0.5;
|
||||
eventBeatSeparator.scrollFactor.set(1, 1);
|
||||
|
||||
bottomSeparator = new FlxSprite(0,-2);
|
||||
bottomSeparator.makeSolid(1, 1, -1);
|
||||
@@ -308,23 +428,32 @@ class EventBackdrop extends FlxBackdrop {
|
||||
public override function draw() {
|
||||
super.draw();
|
||||
|
||||
eventSecSeparator.spacing.y = (10 * Conductor.beatsPerMeasure * Conductor.stepsPerBeat) - 1;
|
||||
eventBeatSeparator.spacing.y = (20 * Conductor.stepsPerBeat) - 1;
|
||||
|
||||
eventSecSeparator.cameras = cameras;
|
||||
eventSecSeparator.x = (x+width) - 20;
|
||||
if (eventSecSeparator.visible) eventSecSeparator.draw();
|
||||
|
||||
eventBeatSeparator.cameras = cameras;
|
||||
eventBeatSeparator.x = (x+width) - 10;
|
||||
if (eventBeatSeparator.visible) eventBeatSeparator.draw();
|
||||
eventBeatSeparator.xPos = x+width;
|
||||
eventBeatSeparator.draw();
|
||||
|
||||
topSeparator.x = (x+width) - 20;
|
||||
topSeparator.cameras = this.cameras;
|
||||
if (!eventSecSeparator.visible) topSeparator.draw();
|
||||
if (!Options.charterShowSections) topSeparator.draw();
|
||||
|
||||
bottomSeparator.x = (x+width) - 20;
|
||||
bottomSeparator.cameras = this.cameras;
|
||||
bottomSeparator.draw();
|
||||
}
|
||||
}
|
||||
class CharterEventGridSeperator extends CharterGridSeperatorBase {
|
||||
public var xPos:Float = 0.0;
|
||||
override private function drawBeats(offset:Float = 0.0) {
|
||||
scale.set(10, 2);
|
||||
updateHitbox();
|
||||
x = xPos-10;
|
||||
super.drawBeats(-2);
|
||||
}
|
||||
override private function drawMeasures(offset:Float = 0.0) {
|
||||
scale.set(20, 4);
|
||||
updateHitbox();
|
||||
x = xPos-20;
|
||||
super.drawMeasures(-3);
|
||||
}
|
||||
override private function drawTimeSignatureChangeGaps() {}
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import funkin.backend.shaders.CustomShader;
|
||||
import funkin.backend.system.Conductor;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.system.FlxAssets.FlxGraphicAsset;
|
||||
import funkin.backend.chart.ChartData.ChartEvent;
|
||||
import funkin.backend.scripting.DummyScript;
|
||||
import funkin.backend.scripting.Script;
|
||||
import funkin.editors.charter.Charter.ICharterSelectable;
|
||||
import funkin.editors.charter.CharterBackdropGroup.EventBackdrop;
|
||||
import funkin.game.Character;
|
||||
import funkin.game.HealthIcon;
|
||||
import openfl.display.BitmapData;
|
||||
|
||||
class CharterEvent extends UISliceSprite implements ICharterSelectable {
|
||||
public var events:Array<ChartEvent>;
|
||||
@@ -45,19 +51,78 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
|
||||
sprite.colorTransform = colorTransform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack data is a list of 4 strings separated by `________PACKSEP________`
|
||||
* [0] Event Name
|
||||
* [1] Event Script
|
||||
* [2] Event JSON Info
|
||||
* [3] Event Icon
|
||||
* [4] Event UI Script / Icon Script
|
||||
**/
|
||||
@:dox(hide) public static function getPackData(name:String):Array<String> {
|
||||
var packFile = Paths.pack('events/${name}');
|
||||
if (Assets.exists(packFile)) {
|
||||
return Assets.getText(packFile).split('________PACKSEP________');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@:dox(hide) public static function getUIScript(event:ChartEvent, caller:String):Script {
|
||||
var uiScript = Paths.script('data/events/${event.name}.ui');
|
||||
var script:Script = null;
|
||||
if(Assets.exists(uiScript)) {
|
||||
script = Script.create(uiScript);
|
||||
} else {
|
||||
var packData = getPackData(event.name);
|
||||
if(packData != null) {
|
||||
var scriptFile = packData[4];
|
||||
if(scriptFile != null) {
|
||||
script = Script.fromString(scriptFile, uiScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(script != null && !(script is DummyScript)) {
|
||||
// classes and functions
|
||||
script.set("EventIconGroup", EventIconGroup); // automatically imported
|
||||
script.set("EventNumber", EventNumber); // automatically imported
|
||||
script.set("getIconFromStrumline", getIconFromStrumline);
|
||||
script.set("getIconFromCharName", getIconFromCharName);
|
||||
script.set("generateDefaultIcon", generateDefaultIcon);
|
||||
script.set("generateEventIconDurationArrow", generateEventIconDurationArrow);
|
||||
script.set("generateEventIconNumbers", generateEventIconNumbers);
|
||||
script.set("generateEventIconWarning", generateEventIconWarning);
|
||||
script.set("getPackData", getPackData);
|
||||
script.set("getEventComponent", getEventComponent);
|
||||
// data
|
||||
script.set("event", event);
|
||||
script.set("caller", caller);
|
||||
|
||||
script.load();
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the default event icon for the wanted event
|
||||
* @param name The name of the event
|
||||
* @return The icon
|
||||
**/
|
||||
private static function generateDefaultIcon(name:String) {
|
||||
var isBase64:Bool = false;
|
||||
var path:String = Paths.image('editors/charter/event-icons/$name');
|
||||
var defaultPath = Paths.image('editors/charter/event-icons/Unknown');
|
||||
if (!Assets.exists(path)) path = defaultPath;
|
||||
if(!Assets.exists(path)) {
|
||||
path = defaultPath;
|
||||
|
||||
var packPath = Paths.pack('events/$name');
|
||||
if (Assets.exists(packPath)) {
|
||||
var packText = Assets.getText(packPath).split('________PACKSEP________');
|
||||
var packImg = packText[3];
|
||||
if(packImg != null && packImg.length > 0) {
|
||||
isBase64 = !packImg.startsWith("assets/");
|
||||
path = packImg;
|
||||
var packData = getPackData(name);
|
||||
if(packData != null) {
|
||||
var packImg = packData[3];
|
||||
if(packImg != null && packImg.length > 0) {
|
||||
isBase64 = !packImg.startsWith("assets/");
|
||||
path = packImg;
|
||||
}
|
||||
}
|
||||
}
|
||||
path = path.trim();
|
||||
@@ -75,27 +140,177 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
|
||||
graphic = defaultPath;
|
||||
}
|
||||
|
||||
return new FlxSprite().loadGraphic(graphic);
|
||||
return new FlxSprite(graphic);
|
||||
}
|
||||
|
||||
public static function generateEventIcon(event:ChartEvent) {
|
||||
return switch(event.name) {
|
||||
default:
|
||||
generateDefaultIcon(event.name);
|
||||
case "Camera Movement":
|
||||
// custom icon for camera movement
|
||||
var state:Charter = cast FlxG.state;
|
||||
if (event.params != null && event.params[0] != null && event.params[0] >= 0 && event.params[0] < state.strumLines.length) {
|
||||
// camera movement, use health icon
|
||||
var icon = Character.getIconFromCharName(state.strumLines.members[event.params[0]].strumLine.characters[0]);
|
||||
var healthIcon = new HealthIcon(icon);
|
||||
healthIcon.setUnstretchedGraphicSize(32, 32, false);
|
||||
healthIcon.scrollFactor.set(1, 1);
|
||||
healthIcon.active = false;
|
||||
healthIcon;
|
||||
} else
|
||||
generateDefaultIcon(event.name);
|
||||
/**
|
||||
* Gets a component sprite from the editors/charter/event-icons/components folder
|
||||
* If you wanna use a number, please use the EventNumber class instead
|
||||
* @param type The type of component to get
|
||||
* @param x The x position of the sprite (optional)
|
||||
* @param y The y position of the sprite (optional)
|
||||
* @return The component sprite
|
||||
**/
|
||||
public static function getEventComponent(type:String, x:Float = 0.0, y:Float = 0.0) {
|
||||
var componentPath = Paths.image("editors/charter/event-icons/components/" + type);
|
||||
if(Assets.exists(componentPath))
|
||||
return new FlxSprite(x, y, componentPath);
|
||||
|
||||
Logs.trace('Could not find component $type', WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expected to be called from inside of a ui script,
|
||||
* calling this elsewhere might cause unexpected results or crashes
|
||||
**/
|
||||
public static function getIconFromStrumline(index:Null<Int>) {
|
||||
var state = cast(FlxG.state, Charter);
|
||||
if (index != null && index >= 0 && index < state.strumLines.length) {
|
||||
return getIconFromCharName(state.strumLines.members[index].strumLine.characters[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getIconFromCharName(name:String) {
|
||||
var icon = Character.getIconFromCharName(name);
|
||||
var healthIcon = new HealthIcon(icon);
|
||||
CoolUtil.setUnstretchedGraphicSize(healthIcon, 32, 32, false);
|
||||
healthIcon.scrollFactor.set(1, 1);
|
||||
healthIcon.active = false;
|
||||
return healthIcon;
|
||||
}
|
||||
|
||||
public static function generateEventIcon(event:ChartEvent, inMenu:Bool = true):FlxSprite {
|
||||
var script = getUIScript(event, "event-icon");
|
||||
if(script != null && !(script is DummyScript)) {
|
||||
script.set("inMenu", inMenu);
|
||||
if(script.get("generateIcon") != null) {
|
||||
var res:FlxSprite = script.call("generateIcon");
|
||||
if(res != null)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
switch(event.name) {
|
||||
case "Time Signature Change":
|
||||
if(event.params != null && (event.params[0] >= 0 || event.params[1] >= 0)) {
|
||||
var group = new EventIconGroup();
|
||||
group.add(generateDefaultIcon(event.name));
|
||||
group.add({ // top
|
||||
var num = new EventNumber(9, -1, event.params[0], EventNumber.ALIGN_CENTER);
|
||||
num.active = false;
|
||||
num;
|
||||
});
|
||||
group.add({ // bottom
|
||||
var num = new EventNumber(9, 10, event.params[1], EventNumber.ALIGN_CENTER);
|
||||
num.active = false;
|
||||
num;
|
||||
});
|
||||
if (Conductor.invalidEvents.contains(event)) generateEventIconWarning(group);
|
||||
return group;
|
||||
}
|
||||
case "Continuous BPM Change":
|
||||
if(event.params != null && event.params[1] != null) {
|
||||
var group = new EventIconGroup();
|
||||
group.add(generateDefaultIcon("BPM Change Start"));
|
||||
if (!inMenu) {
|
||||
generateEventIconDurationArrow(group, event.params[1]);
|
||||
group.members[0].y -= 2;
|
||||
generateEventIconNumbers(group, event.params[0], 3);
|
||||
}
|
||||
if (Conductor.invalidEvents.contains(event)) generateEventIconWarning(group);
|
||||
return group;
|
||||
} else {
|
||||
return generateDefaultIcon("BPM Change Start");
|
||||
}
|
||||
case "BPM Change":
|
||||
if(event.params != null && event.params[0] != null) {
|
||||
var group = new EventIconGroup();
|
||||
group.add(generateDefaultIcon(event.name));
|
||||
if (!inMenu) {
|
||||
group.members[0].y -= 2;
|
||||
generateEventIconNumbers(group, event.params[0], 3);
|
||||
}
|
||||
if (Conductor.invalidEvents.contains(event)) generateEventIconWarning(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
case "Scroll Speed Change":
|
||||
if(event.params != null && !inMenu) {
|
||||
var group = new EventIconGroup();
|
||||
group.add(generateDefaultIcon(event.name));
|
||||
if (event.params[0]) generateEventIconDurationArrow(group, event.params[2]);
|
||||
group.members[0].y -= 2;
|
||||
generateEventIconNumbers(group, event.params[1]);
|
||||
return group;
|
||||
}
|
||||
|
||||
case "Camera Movement":
|
||||
// camera movement, use health icon
|
||||
if(event.params != null) {
|
||||
var icon = getIconFromStrumline(event.params[0]);
|
||||
if(icon != null) return icon;
|
||||
}
|
||||
}
|
||||
return generateDefaultIcon(event.name);
|
||||
}
|
||||
|
||||
private static function generateEventIconNumbers(group:EventIconGroup, number:Float, x:Float = 4, y:Float = 15, spacing:Float = 5, precision:Int = 3) {
|
||||
group.add({
|
||||
var num = new EventNumber(x, y, number, EventNumber.ALIGN_CENTER, spacing, precision);
|
||||
if (num.numWidth > 20) {
|
||||
num.scale.x = num.scale.y = 20 / num.numWidth;
|
||||
}
|
||||
num.active = false;
|
||||
num;
|
||||
});
|
||||
}
|
||||
|
||||
private static function generateEventIconDurationArrow(group:EventIconGroup, stepDuration:Float) {
|
||||
//var group = new EventIconGroup();
|
||||
//group.add(generateDefaultIcon(startIcon));
|
||||
|
||||
var xOffset = 4;
|
||||
var yGap = 24;
|
||||
var endGap = 2;
|
||||
|
||||
if (stepDuration >= 0.55) { //min time for showing arrow
|
||||
var tail = new FlxSprite(xOffset, yGap);
|
||||
var arrow = new FlxSprite(xOffset, (stepDuration * 40) + endGap);
|
||||
var arrowSegment = new FlxSprite(xOffset, yGap);
|
||||
tail.frames = arrow.frames = arrowSegment.frames = Paths.getSparrowAtlas("editors/charter/event-icons/components/arrow-down");
|
||||
|
||||
group.add({
|
||||
tail.animation.addByPrefix("tail", "tail");
|
||||
tail.animation.play("tail");
|
||||
tail;
|
||||
});
|
||||
|
||||
group.add({
|
||||
arrowSegment.animation.addByPrefix("segment", "segment");
|
||||
arrowSegment.animation.play("segment");
|
||||
arrowSegment.scale.y = endGap + (stepDuration * 40) - (tail.height + yGap);
|
||||
arrowSegment.updateHitbox();
|
||||
arrowSegment.y += tail.height;
|
||||
arrowSegment;
|
||||
});
|
||||
|
||||
group.add({
|
||||
arrow.animation.addByPrefix("arrow", "arrow");
|
||||
arrow.animation.play("arrow");
|
||||
arrow;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static function generateEventIconWarning(group:EventIconGroup) {
|
||||
for (spr in group) {
|
||||
spr.colorTransform.redMultiplier = spr.colorTransform.greenMultiplier = spr.colorTransform.blueMultiplier = 0.5;
|
||||
spr.colorTransform.redOffset = 100;
|
||||
}
|
||||
group.add(getEventComponent("warning", 16, -8));
|
||||
group.copyColorTransformToChildren = false;
|
||||
}
|
||||
|
||||
public override function onHovered() {
|
||||
@@ -123,18 +338,150 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
|
||||
}
|
||||
|
||||
for(event in events) {
|
||||
var spr = generateEventIcon(event);
|
||||
var spr = generateEventIcon(event, false);
|
||||
icons.push(spr);
|
||||
members.push(spr);
|
||||
}
|
||||
|
||||
draggable = true;
|
||||
for (event in events)
|
||||
if (event.name == "BPM Change") {
|
||||
draggable = false;
|
||||
break;
|
||||
}
|
||||
|
||||
x = (snappedToGrid && eventsBackdrop != null ? eventsBackdrop.x : 0) - (bWidth = 37 + (icons.length * 22));
|
||||
}
|
||||
}
|
||||
|
||||
class EventIconGroup extends FlxSpriteGroup {
|
||||
public var forceWidth:Float = 16;
|
||||
public var forceHeight:Float = 16;
|
||||
public var dontTransformChildren:Bool = true;
|
||||
public var copyColorTransformToChildren:Bool = true;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
override function preAdd(sprite:FlxSprite):Void
|
||||
{
|
||||
super.preAdd(sprite);
|
||||
sprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
public override function transformChildren<V>(Function:FlxSprite->V->Void, Value:V):Void
|
||||
{
|
||||
if (dontTransformChildren)
|
||||
return;
|
||||
|
||||
super.transformChildren(Function, Value);
|
||||
}
|
||||
|
||||
override function set_x(Value:Float):Float
|
||||
{
|
||||
if (exists && x != Value)
|
||||
transformChildren(xTransform, Value - x); // offset
|
||||
return x = Value;
|
||||
}
|
||||
|
||||
override function set_y(Value:Float):Float
|
||||
{
|
||||
if (exists && y != Value)
|
||||
transformChildren(yTransform, Value - y); // offset
|
||||
return y = Value;
|
||||
}
|
||||
|
||||
override function get_width() {
|
||||
return forceWidth;
|
||||
}
|
||||
override function get_height() {
|
||||
return forceHeight;
|
||||
}
|
||||
|
||||
override public function draw() {
|
||||
@:privateAccess
|
||||
if (copyColorTransformToChildren && colorTransform != null) for (child in members) child.colorTransform.__copyFrom(colorTransform);
|
||||
super.draw();
|
||||
}
|
||||
|
||||
override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
class EventNumber extends FlxSprite {
|
||||
public static inline final ALIGN_NORMAL:Int = 0;
|
||||
public static inline final ALIGN_CENTER:Int = 1;
|
||||
|
||||
public var digits:Array<Int> = [];
|
||||
public static inline final FRAME_POINT:Int = 10;
|
||||
public static inline final FRAME_NEGATIVE:Int = 11;
|
||||
|
||||
public var align:Int = ALIGN_NORMAL;
|
||||
public var spacing:Float = 6;
|
||||
|
||||
public function new(x:Float, y:Float, number:Float, ?align:Int, spacing:Float = 6, precision:Int = 3) {
|
||||
super(x, y);
|
||||
this.digits = [];
|
||||
this.align = align == null ? ALIGN_NORMAL : align;
|
||||
this.spacing = spacing;
|
||||
|
||||
if (number == 0) {
|
||||
this.digits.insert(0, 0);
|
||||
}
|
||||
else {
|
||||
var decimals:Float = FlxMath.roundDecimal(Math.abs(number % 1), precision);
|
||||
if (decimals > 0) this.digits.insert(0, FRAME_POINT);
|
||||
while(decimals > 0) {
|
||||
this.digits.push(Math.floor(decimals * 10));
|
||||
decimals = FlxMath.roundDecimal((decimals * 10) % 1, precision);
|
||||
}
|
||||
|
||||
var ints = Std.int(Math.abs(number));
|
||||
if (ints == 0) this.digits.insert(0, 0);
|
||||
while (ints > 0) {
|
||||
this.digits.insert(0, ints % 10);
|
||||
ints = Std.int(ints / 10);
|
||||
}
|
||||
|
||||
if (number < 0) {
|
||||
this.digits.insert(0, FRAME_NEGATIVE);
|
||||
}
|
||||
}
|
||||
|
||||
loadGraphic(Paths.image('editors/charter/event-icons/components/eventNums'), true, 6, 7);
|
||||
}
|
||||
|
||||
override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
}
|
||||
|
||||
override function draw() {
|
||||
var baseX = x;
|
||||
var offsetX = 0.0;
|
||||
if(align == ALIGN_CENTER) offsetX = -(digits.length - 1) * spacing * Math.abs(scale.x) / 2;
|
||||
|
||||
x = baseX + offsetX;
|
||||
for (i in 0...digits.length) {
|
||||
frame = frames.frames[digits[i]];
|
||||
super.draw();
|
||||
x += spacing * Math.abs(scale.x);
|
||||
}
|
||||
x = baseX;
|
||||
}
|
||||
|
||||
public var numWidth(get, never):Float;
|
||||
private function get_numWidth():Float {
|
||||
return Math.abs(scale.x) * spacing * digits.length;
|
||||
}
|
||||
public var numHeight(get, never):Float;
|
||||
private function get_numHeight():Float {
|
||||
return Math.abs(scale.y) * frameHeight;
|
||||
}
|
||||
|
||||
public override function updateHitbox():Void {
|
||||
var numWidth = this.numWidth;
|
||||
var numHeight = this.numHeight;
|
||||
width = numWidth;
|
||||
height = numHeight;
|
||||
offset.set(-0.5 * (numWidth - spacing * digits.length), -0.5 * (numHeight - frameHeight));
|
||||
centerOrigin();
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class CharterEventScreen extends UISubstateWindow {
|
||||
});
|
||||
eventsList.add(new EventButton(events[events.length-1], CharterEvent.generateEventIcon(events[events.length-1]), events.length-1, this, eventsList));
|
||||
changeTab(events.length-1);
|
||||
}));
|
||||
}, chartEvent.step));
|
||||
for (k=>i in events)
|
||||
eventsList.add(new EventButton(i, CharterEvent.generateEventIcon(i), k, this, eventsList));
|
||||
add(eventsList);
|
||||
@@ -82,12 +82,12 @@ class CharterEventScreen extends UISubstateWindow {
|
||||
else {
|
||||
chartEvent.events = [for (i in eventsList.buttons.members) i.event];
|
||||
chartEvent.refreshEventIcons();
|
||||
Charter.instance.updateBPMEvents();
|
||||
|
||||
Charter.undos.addToUndo(CEditEvent(chartEvent, oldEvents, [for (event in events) Reflect.copy(event)]));
|
||||
}
|
||||
}
|
||||
|
||||
Charter.instance.updateBPMEvents();
|
||||
close();
|
||||
});
|
||||
saveButton.x -= saveButton.bWidth;
|
||||
@@ -112,23 +112,17 @@ class CharterEventScreen extends UISubstateWindow {
|
||||
|
||||
// destroy old elements
|
||||
paramsFields = [];
|
||||
for(e in paramsPanel) {
|
||||
e.destroy();
|
||||
paramsPanel.remove(e);
|
||||
while(paramsPanel.members.length > 0) {
|
||||
var e = paramsPanel.members.pop();
|
||||
if(e != null) {
|
||||
e.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (id >= 0 && id < events.length) {
|
||||
curEvent = id;
|
||||
var curEvent = events[curEvent];
|
||||
eventName.text = curEvent.name;
|
||||
// add new elements
|
||||
var y:Float = eventName.y + eventName.height + 10;
|
||||
for(k=>param in EventsData.getEventParams(curEvent.name)) {
|
||||
function addLabel() {
|
||||
var label:UIText = new UIText(eventName.x, y, 0, param.name);
|
||||
y += label.height + 4;
|
||||
paramsPanel.add(label);
|
||||
};
|
||||
|
||||
var value:Dynamic = CoolUtil.getDefault(curEvent.params[k], param.defValue);
|
||||
var lastAdded = switch(param.type) {
|
||||
@@ -199,6 +193,88 @@ class CharterEventScreen extends UISubstateWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function generateEventUI(event:ChartEvent):Void {
|
||||
var script = CharterEvent.getUIScript(event, "event-ui");
|
||||
if(script != null && !(script is DummyScript)) {
|
||||
script.set("paramsPanel", paramsPanel);
|
||||
script.set("paramsFields", paramsFields);
|
||||
if(script.get("generateUI") != null) {
|
||||
if(script.call("generateUI") == false)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add new elements
|
||||
var _y:Float = eventName.y + eventName.height + 10;
|
||||
var params = EventsData.getEventParams(event.name);
|
||||
for(k=>param in params) {
|
||||
var x = eventName.x + (param.x == null ? 0 : param.x);
|
||||
var y = (param.y == null ? _y : param.y);
|
||||
|
||||
function addLabel() {
|
||||
var label:UIText = new UIText(x, y, 0, param.name);
|
||||
_y += label.height + 4;
|
||||
y += label.height + 4;
|
||||
paramsPanel.add(label);
|
||||
};
|
||||
|
||||
var value:Dynamic = CoolUtil.getDefault(event.params[k], param.defValue);
|
||||
var lastAdded = switch(param.type) {
|
||||
case TString:
|
||||
addLabel();
|
||||
var textBox:UITextBox = new UITextBox(x, y, cast value);
|
||||
paramsPanel.add(textBox); paramsFields.push(textBox);
|
||||
textBox;
|
||||
case TBool:
|
||||
var checkbox = new UICheckbox(x, y, param.name, cast value);
|
||||
paramsPanel.add(checkbox); paramsFields.push(checkbox);
|
||||
checkbox;
|
||||
case TInt(min, max, step):
|
||||
addLabel();
|
||||
var numericStepper = new UINumericStepper(x, y, cast value, CoolUtil.getDefault(step, 1), 0, min, max);
|
||||
paramsPanel.add(numericStepper); paramsFields.push(numericStepper);
|
||||
numericStepper;
|
||||
case TFloat(min, max, step, precision):
|
||||
addLabel();
|
||||
var numericStepper = new UINumericStepper(x, y, cast value, CoolUtil.getDefault(step, 1), precision, min, max);
|
||||
paramsPanel.add(numericStepper); paramsFields.push(numericStepper);
|
||||
numericStepper;
|
||||
case TStrumLine:
|
||||
addLabel();
|
||||
var dropdown = new UIDropDown(x, y, 320, 32, [
|
||||
for(k=>s in cast(FlxG.state, Charter).strumLines.members)
|
||||
'Strumline #${k+1} (${s.strumLine.characters[0]})'
|
||||
], cast value);
|
||||
paramsPanel.add(dropdown); paramsFields.push(dropdown);
|
||||
dropdown;
|
||||
case TColorWheel:
|
||||
addLabel();
|
||||
var colorWheel = new UIColorwheel(x, y, CoolUtil.getColorFromDynamic(value));
|
||||
paramsPanel.add(colorWheel); paramsFields.push(colorWheel);
|
||||
colorWheel;
|
||||
case TDropDown(options):
|
||||
addLabel();
|
||||
var dropdown = new UIDropDown(x, y, 320, 32, options, Std.int(Math.abs(options.indexOf(cast value))));
|
||||
paramsPanel.add(dropdown); paramsFields.push(dropdown);
|
||||
dropdown;
|
||||
default:
|
||||
paramsFields.push(null);
|
||||
null;
|
||||
}
|
||||
if (lastAdded is UISliceSprite)
|
||||
_y += cast(lastAdded, UISliceSprite).bHeight + 4;
|
||||
else if (lastAdded is FlxSprite)
|
||||
_y += cast(lastAdded, FlxSprite).height + 6;
|
||||
}
|
||||
|
||||
if(script != null && !(script is DummyScript)) {
|
||||
if(script.get("postGenerateUI") != null) {
|
||||
script.set("params", params);
|
||||
script.call("postGenerateUI");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function saveCurTab() {
|
||||
if (curEvent < 0) return;
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import funkin.backend.system.Conductor;
|
||||
import funkin.backend.chart.EventsData;
|
||||
|
||||
class CharterEventTypeSelection extends UISubstateWindow {
|
||||
var callback:String->Void;
|
||||
var eventStepTime:Float;
|
||||
|
||||
var buttons:Array<UIButton> = [];
|
||||
|
||||
@@ -13,9 +15,10 @@ class CharterEventTypeSelection extends UISubstateWindow {
|
||||
var upIndicator:UIText;
|
||||
var downIndicator:UIText;
|
||||
|
||||
public function new(callback:String->Void) {
|
||||
public function new(callback:String->Void, eventStepTime:Float) {
|
||||
super();
|
||||
this.callback = callback;
|
||||
this.eventStepTime = eventStepTime;
|
||||
}
|
||||
|
||||
public override function create() {
|
||||
@@ -32,6 +35,15 @@ class CharterEventTypeSelection extends UISubstateWindow {
|
||||
buttonsBG.frames = Paths.getFrames('editors/ui/inputbox');
|
||||
add(buttonsBG);
|
||||
|
||||
var disableConductorEvents:Bool = false;
|
||||
var disableOnlyContinuousChanges:Bool = false;
|
||||
for (change in Conductor.bpmChangeMap) {
|
||||
if (change.continuous && MathUtil.greaterThanEqual(eventStepTime, change.stepTime) && MathUtil.lessThan(eventStepTime, change.endStepTime)) {
|
||||
disableOnlyContinuousChanges = MathUtil.equal(eventStepTime, change.stepTime); //allow time sig and instant bpm changes on the same event
|
||||
disableConductorEvents = !disableOnlyContinuousChanges;
|
||||
}
|
||||
}
|
||||
|
||||
for(k=>eventName in EventsData.eventsList) {
|
||||
var button = new UIButton(0, (32 * k), eventName, function() {
|
||||
close();
|
||||
@@ -52,6 +64,11 @@ class CharterEventTypeSelection extends UISubstateWindow {
|
||||
icon.x = button.x + 8;
|
||||
icon.y = button.y + Math.abs(button.bHeight - icon.height) / 2;
|
||||
add(icon);
|
||||
|
||||
if (disableConductorEvents && (eventName == "Time Signature Change" || eventName == "Continuous BPM Change" || eventName == "BPM Change") || (disableOnlyContinuousChanges && eventName == "Continuous BPM Change")) {
|
||||
button.selectable = button.shouldPress = false;
|
||||
button.autoAlpha = true;
|
||||
}
|
||||
}
|
||||
|
||||
windowSpr.bHeight = 61 + (32 * (17));
|
||||
@@ -79,7 +96,7 @@ class CharterEventTypeSelection extends UISubstateWindow {
|
||||
sinner += elapsed;
|
||||
|
||||
for (button in buttons)
|
||||
button.selectable = buttonsBG.hovered;
|
||||
if (button.shouldPress) button.selectable = buttonsBG.hovered;
|
||||
|
||||
buttonCameras.zoom = subCam.zoom;
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
|
||||
add(new UIText(beatsPerMeasureStepper.x + 30, beatsPerMeasureStepper.y + 3, 0, "/", 22));
|
||||
|
||||
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, metadata.stepsPerBeat, 1, 0, 1, null, 54);
|
||||
add(stepsPerBeatStepper);
|
||||
denominatorStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, Math.floor(16 / metadata.stepsPerBeat), 1, 0, 1, null, 54);
|
||||
add(denominatorStepper);
|
||||
|
||||
add(title = new UIText(songNameTextBox.x, songNameTextBox.y + 10 + 46, 0, "Menus Data (Freeplay/Story)", 28));
|
||||
|
||||
@@ -136,7 +136,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
}
|
||||
|
||||
public function saveMeta() {
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, stepsPerBeatStepper])
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, denominatorStepper])
|
||||
@:privateAccess stepper.__onChange(stepper.label.text);
|
||||
|
||||
var customVals = {};
|
||||
|
||||
@@ -107,8 +107,8 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
|
||||
songDataGroup.add(new UIText(beatsPerMeasureStepper.x + 30, beatsPerMeasureStepper.y + 3, 0, "/", 22));
|
||||
|
||||
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
|
||||
songDataGroup.add(stepsPerBeatStepper);
|
||||
denominatorStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
|
||||
songDataGroup.add(denominatorStepper);
|
||||
|
||||
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (res) {
|
||||
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
|
||||
|
||||
Reference in New Issue
Block a user