diff --git a/assets/data/editors/layouts/stage/spriteEditScreen.xml b/assets/data/editors/layouts/stage/spriteEditScreen.xml index 9c49f410..9c0c20fe 100644 --- a/assets/data/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/data/editors/layouts/stage/spriteEditScreen.xml @@ -119,6 +119,13 @@ button.xml.set(name + "y", y.value); } } + function save(name:String, value:Dynamic) { + button.xml.remove(name); + button.xml.set(name, value); + } + + // TODO: remove old attributes to prevent possible errors + // button.xml.remove(); button.xml.set("name", nameTextBox.label.text); button.xml.set("sprite", spriteTextBox.label.text); diff --git a/assets/data/editors/layouts/stage/stageInfoScreen.xml b/assets/data/editors/layouts/stage/stageInfoScreen.xml new file mode 100644 index 00000000..d5e2bfaf --- /dev/null +++ b/assets/data/editors/layouts/stage/stageInfoScreen.xml @@ -0,0 +1,85 @@ + + + + + + + + + function col(c:Int) { + return MARGIN + (170 + XOFFSET) * c; + } + + for(prop => val in stage.extra) + if(!StringTools.startsWith(prop, "stageEditor.")) + storedProps.push(prop); + + + + + <section> <!-- ROW 1 --> + <set name="curY" value="title.y + TO" /> + + <textbox name="nameTextBox" label="Stage Name" value="stage.stageName" x="col(0)" y="curY" width="200" height="32" /> + <textbox name="spritePathTextBox" value="stage.spritesParentFolder" x="col(1)" y="curY" width="200" height="32" /> + <label text="Sprite Path (Needs Refresh)" x="spritePathTextBox.x" y="spritePathTextBox.y - 14" size="15" /> + </section> + + <section> <!-- ROW 2 --> + <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> + + <label text="Start Cam Pos (X, Y)" x="col(0)" y="curY" /> + <stepper name="camxStepper" value="stage.startCam.x" x="col(0)" y="curY" step="1" width="120" /> + <stepper name="camyStepper" value="stage.startCam.y" x="last.x + last.bWidth + XOFFSET - 30" y="curY" step="1" width="120" /> + + <stepper name="zoomStepper" label="Zoom" value="stage.defaultZoom" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> + </section> + + <section> + <set name="curY" value="camxStepper.y + camxStepper.bHeight + YOFFSET" /> + <set name="listWidth" value="self.winWidth - MARGIN * 2" /> + + <buttonlist name="attributesList" label="Custom Attributes" x="col(0)" y="curY" width="listWidth" height="290" buttonSizeX="listWidth-10" buttonSizeY="35" buttonSpacing="5"> + <texture path="editors/ui/inputbox" /> + <camSpacing value="0" /> + + <code> + import funkin.editors.extra.PropertyButton; + + var buttonList = buttonlist; // important for now, since it gets reset after the code is run + + var width = buttonList.buttonSize.x; + var height = buttonList.buttonSize.y; + + buttonList.addButton.callback = function() { + buttonList.add(new PropertyButton("newProperty", "valueHere", buttonList, width, height, 150, 220, 25)); + } + + //var defaultAttribs = Stage.DEFAULT_ATTRIBUTES; + //for (i in stage.stageXML.attributes()) { + // trace(i, defaultAttribs); + // if (!defaultAttribs.contains(i)) + // buttonList.add(new PropertyButton(i, stage.stageXML.get(i), buttonList, width, height, 150, 220, 25)); + //} + for(key => val in stage.extra) + buttonList.add(new PropertyButton(key, val, buttonList, width, height, 150, 220, 25)); + </code> + </buttonlist> + </section> + + <exec> + function onSave() { + stage.startCam.x = camxStepper.value; + stage.startCam.y = camyStepper.value; + stage.defaultZoom = zoomStepper.value; + stage.stageName = nameTextBox.label.text; + stage.spritesParentFolder = spritePathTextBox.label.text; + + for(prop in storedProps) + stage.extra.remove(prop); + + for(prop in attributesList.buttons.members) + stage.extra.set(prop.propertyText.label.text, prop.valueText.label.text); + } + </exec> +</window> \ No newline at end of file diff --git a/assets/data/editors/layouts/stage/unknownEditScreen.xml b/assets/data/editors/layouts/stage/unknownEditScreen.xml index b2b54542..ec6f3d71 100644 --- a/assets/data/editors/layouts/stage/unknownEditScreen.xml +++ b/assets/data/editors/layouts/stage/unknownEditScreen.xml @@ -56,6 +56,9 @@ button.highMemory = highMemoryRadio.checked; button.lowMemory = lowMemoryRadio.checked; + for (i in xml.attributes()) + xml.remove(i); + for (val in attributesList.buttons.members) xml.set(val.propertyText.label.text, val.valueText.label.text); } diff --git a/assets/data/stages/test.xml b/assets/data/stages/test.xml index be041748..697711bb 100644 --- a/assets/data/stages/test.xml +++ b/assets/data/stages/test.xml @@ -1,6 +1,6 @@ <!-- praying to god we remove this file later on --> -<stage zoom="0.9" name="stage" folder="stages/default/" startCamPosY="600" startCamPosX="1000"> +<stage zoom="0.9" name="stage" folder="stages/default/" startCamPosY="600" startCamPosX="1000" example="value"> <sprite name="normBG" sprite="stagefront" x="-500" y="100" scale="0.75" updateHitbox="true" /> <sprite name="noUpdateHitbox" sprite="stagefront" x="-500" y="300" scale="0.75" /> <sprite name="ro-tat-ay" sprite="stagefront" x="-500" y="700" scale="0.75" updateHitbox="true" angle="37" /> diff --git a/source/funkin/backend/utils/WindowUtils.hx b/source/funkin/backend/utils/WindowUtils.hx index 571f781a..d6210d9a 100644 --- a/source/funkin/backend/utils/WindowUtils.hx +++ b/source/funkin/backend/utils/WindowUtils.hx @@ -28,7 +28,7 @@ class WindowUtils { static var __triedClosing:Bool = false; public static inline function resetClosing() __triedClosing = false; - public static inline function init() { + public static function init() { resetTitle(); resetClosing(); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 2e73cc54..411a1de2 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -96,10 +96,10 @@ class StageEditor extends UIState { } ] }, - /*{ + { label: "Edit", childs: [ - { + /*{ label: "Undo", keybind: [CONTROL, Z], onSelect: _edit_undo, @@ -109,9 +109,25 @@ class StageEditor extends UIState { keybind: [CONTROL, SHIFT, Z], onSelect: _edit_redo, }, - null, + null,*/ + { + label: "Edit Stage Info", + onSelect: (_) -> { + openSubState(new UISoftcodedWindow( + "layouts/stage/stageInfoScreen", + [ + "winTitle" => "Editing Stage Info", + "hasSaveButton" => true, + "hasCloseButton" => true, + "stage" => stage, + "Stage" => Stage, + "exID" => exID + ] + )); + }, + } ] - },*/ + }, { label: "Select", childs: [ @@ -586,6 +602,10 @@ class StageEditor extends UIState { saveToXml(xml, "startCamPosX", stage.startCam.x, 0); saveToXml(xml, "startCamPosY", stage.startCam.y, 0); + for(prop in stage.extra.keys()) + if(!Stage.DEFAULT_ATTRIBUTES.contains(prop) && !prop.startsWith("stageEditor.")) + saveToXml(xml, prop, stage.extra.get(prop)); + var group:Xml = null; var curGroup:String = null; @@ -742,11 +762,11 @@ class StageEditor extends UIState { } }*/ - public function editInfoWithUI() { + /*public function editInfoWithUI() { FlxG.state.openSubState(new StageInfoScreen(stage, (_) -> { if (_ != null) editInfo(_); })); - } + }*/ public function editInfo(newInfo:Xml, addtoUndo:Bool = true) { /*var oldInfo = stage.buildXML(); diff --git a/source/funkin/editors/stage/StageInfoScreen.hx b/source/funkin/editors/stage/StageInfoScreen.hx deleted file mode 100644 index 10fe046b..00000000 --- a/source/funkin/editors/stage/StageInfoScreen.hx +++ /dev/null @@ -1,169 +0,0 @@ -package funkin.editors.stage; - -import flixel.math.FlxPoint; -import funkin.editors.extra.PropertyButton; -import funkin.game.Stage; -import haxe.xml.Access; - -class StageInfoScreen extends UISubstateWindow { - public var stage:Stage; - - public var saveButton:UIButton; - public var closeButton:UIButton; - - public var onSave:(xml:Xml) -> Void = null; - - public function new(stage:Stage, ?onSave:(xml:Xml) -> Void) { - this.stage = stage; - this.onSave = onSave; - super(); - } - - public override function create() { - winTitle = "Editing Stage"; - winWidth = 1014; - winHeight = 600; - - super.create(); - - function addLabelOn(ui:UISprite, text:String) - add(new UIText(ui.x, ui.y - 24, 0, text)); - - /*var title:UIText; - add(title = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Sprite Data", 28)); - - spriteTextBox = new UITextBox(title.x, title.y + title.height + 38, character.sprite, 200); - add(spriteTextBox); - addLabelOn(spriteTextBox, "Sprite"); - - iconTextBox = new UITextBox(spriteTextBox.x + 200 + 26, spriteTextBox.y, character.getIcon(), 150); - iconTextBox.onChange = (newIcon:String) -> {updateIcon(newIcon);} - add(iconTextBox); - addLabelOn(iconTextBox, "Icon"); - - updateIcon(character.getIcon()); - - gameOverCharTextBox = new UITextBox(iconTextBox.x + 150 + (75 + 12), iconTextBox.y, character.gameOverCharacter, 200); - add(gameOverCharTextBox); - addLabelOn(gameOverCharTextBox, "Game Over Character"); - - antialiasingCheckbox = new UICheckbox(spriteTextBox.x, spriteTextBox.y + 10 + 32 + 28, "Antialiasing", character.antialiasing); - add(antialiasingCheckbox); - addLabelOn(antialiasingCheckbox, "Antialiased"); - - flipXCheckbox = new UICheckbox(antialiasingCheckbox.x + 172, spriteTextBox.y + 10 + 32 + 28, "FlipX", character.flipX); - add(flipXCheckbox); - addLabelOn(flipXCheckbox, "Flipped"); - - iconColorWheel = new UIColorwheel(gameOverCharTextBox.x + 200 + 20, gameOverCharTextBox.y, character.iconColor); - add(iconColorWheel); - addLabelOn(iconColorWheel, "Icon Color"); - - add(title = new UIText(spriteTextBox.x, spriteTextBox.y + 10 + 46 + 84, 0, "Character Data", 28)); - - positionXStepper = new UINumericStepper(title.x, title.y + title.height + 36, character.globalOffset.x, 0.001, 2, null, null, 84); - add(positionXStepper); - addLabelOn(positionXStepper, "Position (X,Y)"); - - add(new UIText(positionXStepper.x + 84 - 32 + 0, positionXStepper.y + 9, 0, ",", 22)); - - positionYStepper = new UINumericStepper(positionXStepper.x + 84 - 32 + 26, positionXStepper.y, character.globalOffset.y, 0.001, 2, null, null, 84); - add(positionYStepper); - - cameraXStepper = new UINumericStepper(positionYStepper.x + 36 + 84 - 32, positionYStepper.y, character.cameraOffset.x, 0.001, 2, null, null, 84); - add(cameraXStepper); - addLabelOn(cameraXStepper, "Camera Position (X,Y)"); - - add(new UIText(cameraXStepper.x + 84 - 32 + 0, cameraXStepper.y + 9, 0, ",", 22)); - - cameraYStepper = new UINumericStepper(cameraXStepper.x + 84 - 32 + 26, cameraXStepper.y, character.cameraOffset.y, 0.001, 2, null, null, 84); - add(cameraYStepper); - - scaleStepper = new UINumericStepper(cameraYStepper.x + 84 - 32 + 90, cameraYStepper.y, character.scale.x, 0.001, 2, null, null, 74); - add(scaleStepper); - addLabelOn(scaleStepper, "Scale"); - - singTimeStepper = new UINumericStepper(scaleStepper.x + 74 - 32 + 36, scaleStepper.y, character.holdTime, 0.001, 2, null, null, 74); - add(singTimeStepper); - addLabelOn(singTimeStepper, "Sing Duration (Steps)"); - - customPropertiesButtonList = new UIButtonList<PropertyButton>(singTimeStepper.x + singTimeStepper.width + 200, singTimeStepper.y, 290, 200, '', FlxPoint.get(280, 35), null, 5); - customPropertiesButtonList.frames = Paths.getFrames('editors/ui/inputbox'); - customPropertiesButtonList.cameraSpacing = 0; - customPropertiesButtonList.addButton.callback = function() { - customPropertiesButtonList.add(new PropertyButton("newProperty", "valueHere", customPropertiesButtonList)); - } - for (prop=>val in character.extra) - customPropertiesButtonList.add(new PropertyButton(prop, val, customPropertiesButtonList)); - add(customPropertiesButtonList); - addLabelOn(customPropertiesButtonList, "Custom Values (Advanced)"); - - isPlayerCheckbox = new UICheckbox(positionXStepper.x, positionXStepper.y + 10 + 32 + 28, "isPlayer", character.playerOffsets); - add(isPlayerCheckbox); - addLabelOn(isPlayerCheckbox, "Is Player"); - - isGFCheckbox = new UICheckbox(isPlayerCheckbox.x + 128, positionXStepper.y + 10 + 32 + 28, "isGF", character.isGF); - add(isGFCheckbox); - addLabelOn(isGFCheckbox, "Is GF"); - - for (checkbox in [isPlayerCheckbox, isGFCheckbox, antialiasingCheckbox, flipXCheckbox]) - {checkbox.y += 4; checkbox.x += 6;}*/ - - saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight- 20, "Save & Close", function() { - //saveCharacterInfo(); - close(); - }, 125); - saveButton.x -= saveButton.bWidth; - saveButton.y -= saveButton.bHeight; - - closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { - if (onSave != null) onSave(null); - close(); - }, 125); - closeButton.x -= closeButton.bWidth; - closeButton.color = 0xFFFF0000; - add(closeButton); - add(saveButton); - } - - /*function saveCharacterInfo() { - for (stepper in [positionXStepper, positionYStepper, cameraXStepper, cameraYStepper, singTimeStepper, scaleStepper]) - @:privateAccess stepper.__onChange(stepper.label.text); - - var xml = Xml.createElement("character"); - xml.set("isPlayer", isPlayerCheckbox.checked ? "true" : "false"); - xml.set("isGF", isGFCheckbox.checked ? "true" : "false"); - xml.set("x", Std.string(positionXStepper.value)); - xml.set("y", Std.string(positionYStepper.value)); - xml.set("gameOverChar", gameOverCharTextBox.label.text); - xml.set("camx", Std.string(cameraXStepper.value)); - xml.set("camy", Std.string(cameraYStepper.value)); - xml.set("holdTime", Std.string(singTimeStepper.value)); - xml.set("flipX", Std.string(flipXCheckbox.checked)); - xml.set("icon", iconTextBox.label.text); - xml.set("scale", Std.string(scaleStepper.value)); - xml.set("antialiasing", antialiasingCheckbox.checked ? "true" : "false"); - xml.set("sprite", spriteTextBox.label.text); - if (iconColorWheel.colorChanged) - xml.set("color", iconColorWheel.curColor.toWebString()); - for (val in customPropertiesButtonList.buttons.members) - xml.set(val.propertyText.label.text, val.valueText.label.text); - - for (anim in character.animDatas) - { - var animXml:Xml = Xml.createElement('anim'); - animXml.set("name", anim.name); - animXml.set("anim", anim.anim); - animXml.set("loop", Std.string(anim.loop)); - animXml.set("fps", Std.string(anim.fps)); - var offset:FlxPoint = character.getAnimOffset(anim.name); - animXml.set("x", Std.string(offset.x)); - animXml.set("y", Std.string(offset.y)); - if (anim.indices.length > 0) - animXml.set("indices", anim.indices.join(",")); - xml.addChild(animXml); - } - - if (onSave != null) onSave(xml); - }*/ -} \ No newline at end of file diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index a621dc83..f4f13d70 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -57,6 +57,8 @@ class Stage extends FlxBasic implements IBeatReceiver { if (autoLoad) loadXml(stageXML); } + public static var DEFAULT_ATTRIBUTES:Array<String> = ["name", "startCamPosX", "startCamPosY", "zoom", "folder"]; + public function loadXml(xml:Access, forceLoadAll:Bool = false) { if (PlayState.instance == state) { stageScript = Script.create(Paths.script('data/stages/$stageFile')); @@ -83,6 +85,11 @@ class Stage extends FlxBasic implements IBeatReceiver { if (!spritesParentFolder.endsWith("/")) spritesParentFolder += "/"; } + // Load custom attributes + for(att in xml.x.attributes()) + if(!DEFAULT_ATTRIBUTES.contains(att)) + extra.set(att, xml.x.get(att)); + var elems:Array<Access> = []; // some way to tag that the sprites are from the group for(node in xml.elements) {