diff --git a/README.md b/README.md index 3cae8c2..24cfc4d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ # Version 2.0.0 Breaking Changes -...or not? They're just really big and I don't want it to mess up other developments - -(so, more like Version 2.0.0 Big Changes) +They're really big and I don't want it to mess up other developments Putting fundamental changes intended for v2.0.0 here diff --git a/source/chartformat/ChartFormat.hx b/source/chartformat/ChartFormat.hx new file mode 100644 index 0000000..4040a40 --- /dev/null +++ b/source/chartformat/ChartFormat.hx @@ -0,0 +1,201 @@ +package chartformat; + +class ChartFormat { + //basic info + public var song:String; + public var title:Null; + public var bpm:Float = 100.0; + public var speed:Float = 1.0; + public var attributes:Array>; + + //gameplay + public var validScore:Bool = true; + public var events:Array; + public var notes:Array; + + public function new(song:String) { + this.song = song; + attributes = new Array>(); + events = new Array(); + notes = new Array(); + setAttributesFromMap([ + "noteTypes" => ["Normal Note"] + ]); + } + + public function getAttribute(name:String) { + for (thing in attributes) { + if (thing[0] == name) + return thing; + } + return [name]; + } + + public function setAttribute(dat:Array) { + for (i => thing in attributes.keyValueIterator()) { + if (thing[0] == dat[0]) + return attributes[i] = dat; + } + attributes.push(dat); + return dat; + } + + public function setAttributesFromMap(attrib:Map>) { + attributes.resize(0); + for (n => dat in attrib) { + attributes.push(cast([n], Array).concat(dat)); + } + } + + public function addAttributesFromMap(attrib:Map>) { + for (n => dat in attrib) { + setAttribute(cast([n], Array).concat(dat)); + } + } + + public function attributesToMap() { + var result = new Map>(); + for (thing in attributes) { + result.set(thing[0], thing.slice(1)); + } + return result; + } + + inline static function condSet(map, cond, name, val) { + if (cond) + map.set(name, val); + } + + public static function fromOld(dat:ChartFormatOld) { + var result = new ChartFormat(dat.song); + result.title = dat.newtitle; + result.bpm = dat.bpm; + result.speed = dat.speed; + result.validScore = dat.validScore; + var attributes = new Map>(); + var empty = new Array(); + if (dat.attributes == null) { + for (thing in dat.attributes) { + var newAttribute = []; + for (n in thing) { + newAttribute.push(Std.string(n)); + } + attributes.set(newAttribute.shift(), newAttribute); + } + } + for (thing in dat.actions) + attributes.set(thing, empty); + attributes.set("healthDrain", [Std.string(dat.healthDrain == null ? 0 : dat.healthDrain), Std.string(dat.healthDrainMin == null ? 0 : dat.healthDrainMin)]); + condSet(attributes, dat.usedNoteTypes != null && dat.usedNoteTypes.length != 0, "noteTypes", dat.usedNoteTypes); + condSet(attributes, dat.hide_girlfriend == true, "hideGirlfriend", empty); + condSet(attributes, dat.moreStrumLines == null, "strumLineCount", [Std.string(dat.moreStrumLines + 2)]); + attributes.set("voicesName", [dat.voicesName]); + condSet(attributes, dat.needsVoices == false, "needsVoices", [false]); + attributes.set("instName", [dat.instName]); + attributes.set("voicesOpponentName", [dat.voicesOpponentName]); + condSet(attributes, dat.threeLanes == true, "threeLanes", empty); + condSet(attributes, dat.picospeaker != null && dat.picospeaker != "", "picoSpeaker", [dat.picospeaker]); + condSet(attributes, dat.picocharts != null && dat.picocharts.length != 0, "linkedCharts", dat.picocharts); + condSet(attributes, dat.loopbackPoint != null, "loopTime", [Std.string(dat.loopbackPoint)]); + condSet(attributes, dat.timeSignature != null && dat.timeSignature != 4, "sectionBeats", [Std.string(dat.timeSignature)]); + + attributes.set("characters", [dat.player1 == null ? "bf" : dat.player1, dat.player2 == null ? "mr_placeholder_guy" : dat.player2, dat.gfVersion == null ? "gf" : dat.gfVersion].concat(dat.moreCharacters == null ? [] : dat.moreCharacters)); + condSet(attributes, dat.stage != "stage" && dat.stage != null, "stage", [dat.stage]); + condSet(attributes, dat.noteSkin != null && dat.noteSkin != "normal" && dat.noteSkin != "" && dat.noteSkinOpponent != null && dat.noteSkinOpponent.length != 0, "noteSkin", dat.noteSkinOpponent != null ? [dat.noteSkin].concat(dat.noteSkinOpponent) : [dat.noteSkin]); + condSet(attributes, dat.uiStyle != null && dat.uiStyle != "" && dat.uiStyle != "normal", "uiStyle", [dat.uiStyle]); + result.setAttributesFromMap(attributes); + //this is wacky + + //todo: notes and events + } + + public static function fromPsych(dat:ChartFormatPsych) { + var result = new ChartFormat(dat.song); + result.bpm = dat.bpm; + result.speed = dat.speed; + result.validScore = true; + + var attributes = new Map>(); + attributes.set("characters", [dat.player1, dat.player2]); + attributes.set("stage", [dat.stage]); + condSet(attributes, dat.needsVoices == false, "needsVoices", [false]); + result.setAttributesFromMap(attributes); + + var noteTypes:Array = ["Normal Note"]; + var ntOld = ['Normal Note', 'Alt Animation', 'Hey', 'Hurt Note', 'GF Sing', 'No Animation']; + for (section in dat.notes) { + var newSection:SectionFormatVE = { + notes: [], + chars: section.gfSection ? [2, section.mustHitSection ? 1 : 0] : null, + bpm: section.changeBPM ? section.bpm : null, + mania: null, + mustHitSection: section.mustHitSection, + focusCharacter: section.gfSection ? 2 : null, + beats: section.sectionBeats + } + for (note in section.sectionNotes) { + var nt:String = (note.length < 4 || note[3] == null) ? "Normal Note" : (Std.isOfType(note[3], String) ? note[3] : ntOld[note[3]]); + newSection.notes.push({ + t: note[0], + d: note[1], + l: note[2], + n: noteTypes.indexOf(nt) + }); + } + result.notes.push(newSection); + } + + //todo: events + + return result; + } + + public static function fromLeather(dat:ChartFormatLeather) { + var result = new ChartFormat(dat.song); + result.bpm = dat.bpm; + result.speed = dat.speed; + result.validScore = dat.validScore; + + var attributes = new Map>(); + var gf = dat.gf; + if (gf == null) + gf = dat.gfVersion == null ? dat.player3 : dat.gfVersion; + attributes.set("characters", [dat.player1, dat.player2, gf]); + if (dat.specialAudioName != null) { + attributes.set("instName", ["Inst-" + dat.specialAudioName]); + attributes.set("voicesName", ["Voices-" + dat.specialAudioName]); + } + if (dat.keyCount != null || dat.playerKeyCount != null) { + var kc = dat.keyCount == null ? 4 : dat.keyCount; + attributes.set("mania", [(dat.playerKeyCount != null ? dat.playerKeyCount : kc) + "k", kc + "k"]); + } + if (dat.ui_Skin != null) { + attributes.set("uiStyle", [dat.ui_Skin]); + attributes.set("noteSkin", [dat.ui_Skin]); + } + + //todo: notes and events + } +} + +typedef SectionFormatVE = { + var notes:Array; + var chars:Null>; + var bpm:Float; + var mania:Null>>; + var mustHitSection:Bool; + var focusCharacter:Null; + var beats:Float; +} + +typedef NoteFormatVE = { + var t:Float; //strumTime + var d:Int; //noteData + var l:Float; //sustainLength + var n:Int; //noteType +} + +typedef EventFormatVE = { + var t:Float; //strumTime + var d:Int; //index in attributes -> "events" +} \ No newline at end of file diff --git a/source/chartformat/ChartFormatDetector.hx b/source/chartformat/ChartFormatDetector.hx new file mode 100644 index 0000000..dd47df3 --- /dev/null +++ b/source/chartformat/ChartFormatDetector.hx @@ -0,0 +1,2 @@ +package chartformat; + diff --git a/source/chartformat/ChartFormatLeather.hx b/source/chartformat/ChartFormatLeather.hx new file mode 100644 index 0000000..073cfbf --- /dev/null +++ b/source/chartformat/ChartFormatLeather.hx @@ -0,0 +1,51 @@ +package chartformat; + +typedef ChartFormatLeather = { + var song:String; + var notes:Array; + var bpm:Float; + var needsVoices:Bool; + var speed:Float; + + var player1:String; + var player2:String; + var gf:Null; + var stage:String; + var validScore:Bool; + var modchartPath:String; + var keyCount:Null; + var playerKeyCount:Null; + var timescale:Array; + var chartOffset:Null; // in milliseconds + // shaggy pog + var mania:Null; + var ui_Skin:Null; + var cutscene:String; + var endCutscene:String; + var eventObjects:Array; + var events:Null>>; + var specialAudioName:Null; + var gfVersion:Null; + var player3:Null; +} + +typedef SectionFormatLeather = +{ + var sectionNotes:Array; + var lengthInSteps:Int; + var typeOfSection:Int; + var mustHitSection:Bool; + var bpm:Float; + var changeBPM:Bool; + var altAnim:Bool; + + var timeScale:Array; + var changeTimeScale:Bool; +} + +typedef EventFormatLeather = { + var name:String; + var position:Float; + var value:Float; + var type:String; +} \ No newline at end of file diff --git a/source/chartformat/ChartFormatOld.hx b/source/chartformat/ChartFormatOld.hx new file mode 100644 index 0000000..2363a85 --- /dev/null +++ b/source/chartformat/ChartFormatOld.hx @@ -0,0 +1,77 @@ +package chartformat; + +typedef ChartFormatOld = { + var song:String; + var newtitle:Null; //display name + var notes:Array; + var bpm:Float; + var needsVoices:Bool; + var speed:Float; + + var player1:String; + var player2:String; + var validScore:Bool; + + var gfVersion:String; + var maniaStr:Null; + var mania:Null; //for Kade/Psych (7k and 9k vs shaggy charts dont get interpreted right) + var keyCount:Null; //for Leather + var stage:String; + var usedNoteTypes:Array; + + var healthDrain:Null; + var healthDrainMin:Null; + + var moreCharacters:Array; + + var actions:Array; + var attributes:Array>; + var noteSkin:String; + var noteSkinOpponent:Array; + var uiStyle:String; + + var vmanEventTime:Array; + var vmanEventOrder:Array; + var vmanEventData:Array; + + var hide_girlfriend:Null; + + var moreStrumLines:Null; + + var timeSignature:Null; + + var voicesName:Null; + var voicesOpponentName:Null; + var instName:Null; + + var threeLanes:Null; //Pasta night :)))))) + + var picospeaker:Null; //Week 7 stress + var picocharts:Null>; //It dont Crap + + var loopbackPoint:Null; //Music that is just endless on it's own +} + +typedef SectionFormatOld = { + var sectionNotes:Array>; // putting here so i remember: + //sectionNotes[i][0]: strumTime + //sectionNotes[i][1]: noteData + //sectionNotes[i][2]: sustainLength + //sectionNotes[i][3]: noteType + var notesMoreLayers:Array>>; + var lengthInSteps:Int; + var typeOfSection:Int; + var mustHitSection:Bool; + var bpm:Float; + var changeBPM:Bool; + var altAnim:Bool; + var gfSection:Bool; + var focusCharacter:Null; + var changeMania:Bool; + //var maniaArr:Array; + var maniaStr:String; + var changeTimeSignature:Bool; + var timeSignature:Int; + var sectionBeats:Int; + var dType:Int; //this exists because Final Destination!!! +} \ No newline at end of file diff --git a/source/chartformat/ChartFormatPsych.hx b/source/chartformat/ChartFormatPsych.hx new file mode 100644 index 0000000..6f81fc9 --- /dev/null +++ b/source/chartformat/ChartFormatPsych.hx @@ -0,0 +1,37 @@ +package chartformat; + +typedef ChartFormatPsych = +{ + var song:String; + var notes:Array; + var events:Array; + var bpm:Float; + var needsVoices:Bool; + var speed:Float; + + var player1:String; + var player2:String; + var gfVersion:String; + var stage:String; + + @:optional var gameOverChar:String; + @:optional var gameOverSound:String; + @:optional var gameOverLoop:String; + @:optional var gameOverEnd:String; + + @:optional var disableNoteRGB:Bool; + + @:optional var arrowSkin:String; + @:optional var splashSkin:String; +} + +typedef SectionFormatPsych = +{ + var sectionNotes:Array; + var sectionBeats:Float; + var mustHitSection:Bool; + var gfSection:Bool; + var bpm:Float; + var changeBPM:Bool; + var altAnim:Bool; +} \ No newline at end of file diff --git a/source/chartformat/HealthDrainMethod.hx b/source/chartformat/HealthDrainMethod.hx new file mode 100644 index 0000000..a3dad1d --- /dev/null +++ b/source/chartformat/HealthDrainMethod.hx @@ -0,0 +1,151 @@ +package chartformat; + +import flixel.math.FlxMath; +import PlayState; +import Note; +import Scripting; + +class HealthDrainMethodNone { + public function new() {} + + public function setAttribute(num:Int, val:Float) {} + + public function opponentNoteHit(note:Note, state:PlayState) { + //do nothing + return state.health; + } +} + +class HealthDrainMethodFatal extends HealthDrainMethodNone { + public var amount:Float = 0.02; + + public override function setAttribute(num:Int, val:Float) { + switch(num) { + case 0: + amount = val; + } + } + + public override function opponentNoteHit(note:Note, state:PlayState) { + return state.health -= amount; + } +} + +class HealthDrainMethod extends HealthDrainMethodFatal { + public static function getHealthDrainMethod(name:String):HealthDrainMethodNone { + switch(name.toLowerCase()) { + case "fatal": + return new HealthDrainMethodFatal(); + case "normal": + return new HealthDrainMethod(); + case "script": + return new HealthDrainMethodCustom(); + case "enforcer": + return new HealthDrainMethodEnforcer(); + case "smoothenforcer": + return new HealthDrainMethodSmoothEnforcer(); + case "multiplyaddfatal": + return new HealthDrainMethodMultiplyAddFatal(); + case "multiplyadd": + return new HealthDrainMethodMultiplyAdd(); + } + return new HealthDrainMethodNone(); + } + + public var min:Float = 0.05; + + public override function setAttribute(num:Int, val:Float) { + switch(num) { + case 0: + amount = val; + case 1: + min = val; + } + } + + public override function opponentNoteHit(note:Note, state:PlayState) { + if (state.health > min) + return state.health = Math.max(min, state.health - amount); + return state.health; + } +} + +class HealthDrainMethodCustom extends HealthDrainMethod { + public dynamic function healthDrainFunc(note:Note, state:PlayState) { + return state.health; + } + + public override function setAttribute(num:Int, val:Float) { + Scripting.runOnScripts("customHealthDrainMethod", [this, num, val]); + } + + public override function opponentNoteHit(note:Note, state:PlayState) { + return healthDrainFunc(note, state); + } +} + +class HealthDrainMethodEnforcer extends HealthDrainMethod { + public var threshold:Float = 1.5; + public var thresholdAmount:Float = 0.1; + + override function opponentNoteHit(note:Note, state:PlayState) { + if (state.health > threshold) + return state.health = Math.max(min, state.health - threshold); + return super.opponentNoteHit(note, state); + } +} + +class HealthDrainMethodSmoothEnforcer extends HealthDrainMethod { + public var threshold:Float = 1.5; + public var thresholdTop:Float = 1.75; + public var thresholdAmount:Float = 0.1; + + override function opponentNoteHit(note:Note, state:PlayState) { + if (state.health > threshold) + return state.health = Math.max(min, state.health - FlxMath.lerp(FlxMath.bound(FlxMath.remapToRange(state.health, threshold, thresholdTop, 0, 1), 0, 1), amount, thresholdAmount)); + return super.opponentNoteHit(note, state); + } +} + +class HealthDrainMethodMultiplyAddFatal extends HealthDrainMethodFatal { + public var offset:Float = 0.01; + + public override function new() { + super(); + amount = 0.975; + } + + public override function setAttribute(num:Int, val:Float) { + switch(num) { + case 0: + amount = val; + case 1: + offset = val; + } + } + + public override function opponentNoteHit(note:Note, state:PlayState) { + return state.health = (state.health * amount) - offset; + } +} + +class HealthDrainMethodMultiplyAdd extends HealthDrainMethodMultiplyAddFatal { + public var min:Float = 0.05; + + public override function setAttribute(num:Int, val:Float) { + switch(num) { + case 0: + amount = val; + case 1: + offset = val; + case 2: + min = val; + } + } + + public override function opponentNoteHit(note:Note, state:PlayState) { + if (state.health > min) + return state.health = Math.max(min, (state.health * amount) - offset); + return state.health; + } +} \ No newline at end of file