EDIT: Nevermind, I figured it out. So basically, I'm creating a castle that's in a state of disrepair, using custom assets I've created myself. The plan is to enable the player to "repair" each individual object, by using something similar to the crafting GUI. For example: This is a castle banner in a state of disrepair. The idea is to "repair" it using materials, in this case 6 silk, 2 string, 1 pink dye, and 100 pixels. The end result would be this: I started off using the same script that upgradeable crafting stations use. In the list of craftable materials, I included the items needed for repairing this object. To "repair" the object, for now I'm using the upgrade button at the top. I've made a lot of progress on my own. For now, treating the initial damaged object as a crafting station and using the script mentioned earlier seems to work fine up to the point of "repairing" the object. Now here's what I'm struggling with: Once the item is "repaired", I want it to go back to being a decorative object instead of a crafting station. Just to try it, I added the line "category": "decorative", in the "itemSpawnParameters" for the second version of the crafting station, aka the repaired banner. As I expected, it didn't work, and the banner remains a crafting station. I imagine I'd need to edit the lua script to get the desired result, and my skill with lua is still a work in progress. So I guess what I'm asking is, can anyone lead me on the right track? I'm not asking for anyone to actually write code for me, but if you could help me figure out where to start, that would be very helpful. The goal is to upgrade a crafting station into a decorative object. .object file: Code: { "objectName": "brokenbannerpinklarge", "colonyTags": [], "rarity": "Legendary", "description": "A woven pink banner. Looks like it's seen better days.", "shortdescription": "Worn Large Pink Banner", "category": "crafting", "price": 626, "printable": false, "breakDropOptions": [], "scripts": ["/objects/crafting/upgradeablecraftingobjects/upgradeablecraftingobject.lua"], "animation" : "bannerpinklarge.animation", "orientations": [{ "dualImage": "brokenbannerpinklarge.png:<color>", "imagePosition": [0, 0], "spaceScan": 0.1, "bgAnchors": [ [-1, 0], [0, 0], [1, 0] ] }, { "dualImage": "brokenbannerpinklarge.png:<color>", "imagePosition": [0, 0], "spaceScan": 0.1, "fgAnchors": [ [-1, 1], [0, 1], [1, 1] ] }], "startingUpgradeStage": 1, "maxUpgradeStage": 2, "upgradeStages": [{ "animationState": "brokenbannerpinklarge", "itemSpawnParameters": { "inventoryIcon": "bannerpinklargeicon.png", "placementImage": "brokenbannerpinklarge.png:default", "placementImagePosition": [-8, -32], "description": "A woven pink banner. Looks like it's seen better days.", "shortdescription": "Worn Large Pink Banner", "floranDescription": "Floran wonder what big banner look like before.", "glitchDescription": "Morose. This banner has fallen into disrepair." }, "interactData": { "config": "/interface/windowconfig/craftingcastle_sewing.config", "paneLayoutOverride": { "windowtitle": { "title": "Castle Repair", "subtitle": "^#b9b5b2;It's just a fixer-upper.", "icon": { "file": "/interface/crafting/craftingcastle.png" } } }, "filter": ["craftingcastle"], "initialRecipeUnlocks": [], "upgradeMaterials": [{ "item": "silk", "count": 6 }, { "item": "string", "count": 2 }, { "item": "pinkdye", "count": 1 }, { "item": "money", "count": 626 }] }, "learnBlueprintsOnPickup": [], "upgradeSoundEffect": "fanfare" }, { "animationState": "bannerpinklarge", "itemSpawnParameters": { "price": 626, "category": "decorative", "inventoryIcon": "bannerpinklargeicon.png", "placementImage": "bannerpinklarge.png:default", "placementImagePosition": [-8, -32], "description": "A beautifully woven pink banner.", "shortdescription": "Large Pink Banner", "floranDescription": "Sssilky banner.", "glitchDescription": "Proud. The Glitch produce banners of all kinds. They symbolize the different houses of the Glitch." }, "interactData": {} } ] } .animation file: Code: { "animatedParts" : { "stateTypes" : { "stage" : { "default" : "brokenbannerpinklarge", "states" : { "brokenbannerpinklarge" : {}, "bannerpinklarge" : {} } } }, "parts" : { "lights" : { "properties" : { "centered" : false, "fullbright" : false, "zLevel" : 0 }, "partStates" : { "stage" : { "brokenbannerpinklarge" : {}, "bannerpinklarge" : {} } } }, "chassis" : { "properties" : { "centered" : false, "zLevel" : 1 }, "partStates" : { "stage" : { "brokenbannerpinklarge" : { "properties" : { "image" : "brokenbannerpinklarge.png:<color>" } }, "bannerpinklarge" : { "properties" : { "image" : "bannerpinklarge.png:<color>" } } } } } } }, "sounds" : { "fanfare" : ["/sfx/interface/crafting_sewing.ogg"] }, "lights" : {}, "particleEmitters" : {} } craftingcastle_sewing.config file: Code: { "noCategoryFilters" : false, "filter" : [ ], "titleFromEntity" : true, "requiresBlueprint" : false, "craftingSound" : "/sfx/interface/crafting_money.ogg", "paneLayout" : { "background" : { "type" : "background", "fileHeader" : "/interface/crafting/craftingheader.png", "fileBody" : "/interface/crafting/craftingbody.png", "fileFooter" : "/interface/crafting/craftingfooter.png" }, "close" : { "type" : "button", "base" : "/interface/inventory/x.png", "hover" : "/interface/inventory/xhover.png", "press" : "/interface/inventory/xpress.png", "position" : [321, 261] }, "windowtitle" : { "type" : "title", "title" : "Castle Repair", "subtitle" : " ^#b9b5b2;It's just a fixer-upper.", "position" : [-5, 252], "icon" : { "type" : "image", "file": "/interface/crafting/craftingcastle.png", "position" : [0, -20], "zlevel" : -1 } }, "bgShine" : { "type" : "image", "file" : "/interface/crafting/shine.png", "position" : [-15, 0], "zlevel" : -10 }, "btnUpgrade" : { "type" : "button", "disabledImage" : "/interface/crafting/upgradeUnready.png", "base" : "/interface/crafting/upgradeReady.png", "position" : [139, 258], "zlevel" : 5 }, "lblSchematics" : { "type" : "label", "position" : [88, 245], "hAnchor" : "mid", "value" : "^#b9b5b2;BLUEPRINTS" }, "lblProducttitle" : { "type" : "label", "position" : [265, 245], "hAnchor" : "mid", "value" : "^#b9b5b2;PRODUCT" }, "spinCount" : { "type" : "spinner", "position" : [220, 46], "upOffset" : 36 }, "tbSpinCount" : { "type" : "textbox", "position" : [232, 46], "textAlign" : "center", "maxWidth" : 16, "regex" : "x?\\d{0,4}", "hint" : "" }, "imgAmountInput" : { "type" : "image", "file" : "/interface/crafting/amount.png", "position" : [226, 45], "zlevel" : -3 }, "btnCraft" : { "type" : "button", "base" : "/interface/button.png", "hover" : "/interface/buttonhover.png", "position" : [271, 43], "caption" : "Craft" }, "btnStopCraft" : { "type" : "button", "base" : "/interface/buttonactive.png", "hover" : "/interface/buttonactivehover.png", "position" : [271, 43], "caption" : "Stop" }, "imgCraftBg" : { "type" : "image", "file" : "/interface/crafting/craftbg.png", "position" : [196, 40], "zlevel" : -5 }, "currentRecipeIcon" : { "type" : "itemslot", "callback" : "null", "position" : [197, 41] }, "btnFilterHaveMaterials" : { "type" : "button", "base" : "/interface/crafting/checkboxnocheck.png", "baseImageChecked" : "/interface/crafting/checkboxcheck.png", "checkable" : true, "checked" : false, "position" : [40, 59] }, "lblProduct" : { "type" : "label", "position" : [51, 58], "hAnchor" : "left", "value" : "MATERIALS AVAILABLE" }, "scrollArea" : { "type" : "scrollArea", "rect" : [5, 69, 174, 230], "children" : { "itemList" : { "type" : "list", "schema" : { "selectedBG" : "/interface/crafting/craftableselected2.png", "unselectedBG" : "/interface/crafting/craftablebackground.png", "spacing" : [0, 1], "memberSize" : [159, 20], "listTemplate" : { "background" : { "type" : "image", "file" : "/interface/crafting/craftablebackground.png", "position" : [2, 0], "zlevel" : -1 }, "itemName" : { "type" : "label", "position" : [25, 5], "hAnchor" : "left", "wrapWidth" : 116, "value" : "Replace Me" }, "itemIcon" : { "type" : "itemslot", "position" : [3, 1], "callback" : "null" }, "newIcon" : { "type" : "image", "position" : [119, 5], "file" : "/interface/crafting/new.png", "zlevel" : 2 }, "moneyIcon" : { "type" : "image", "position" : [122, 1], "file" : "/interface/money.png" }, "priceLabel" : { "type" : "label", "position" : [134, 1], "hAnchor" : "left", "value" : "0" }, "notcraftableoverlay" : { "type" : "image", "file" : "/interface/crafting/notcraftableoverlay.png", "position" : [2, 0], "zlevel" : 1 } } } } } }, "description" : { "type" : "widget", "position" : [190, 41], "size" : [140, 220] }, "filter" : { "type" : "textbox", "position" : [60, 43], "hint" : "Search", "maxWidth" : 70, "escapeKey" : "close", "enterKey" : "filter", "focus" : true }, "categories" : { "type" : "radioGroup", "toggleMode" : true, "buttons" : [ ] }, "rarities" : { "type" : "radioGroup", "toggleMode" : true, "buttons" : [ ] } } } upgradeablecraftingobject.lua file (vanilla asset): Code: require "/scripts/vec2.lua" require "/scripts/util.lua" function init() object.setInteractive(true) self.maxUpgradeStage = config.getParameter("maxUpgradeStage") if not storage.currentStage then storage.currentStage = math.min(config.getParameter("startingUpgradeStage", 1), self.maxUpgradeStage) end self.stageDataList = config.getParameter("upgradeStages") -- handle upgrade messages from the crafting interface message.setHandler("requestUpgrade", function(_, _) upgradeTo(storage.currentStage, storage.currentStage + 1) end) updateStageData() if ObjectAddons then local addonConfig = currentStageData().addonConfig ObjectAddons:init(addonConfig or {}, updateStageData) end end function uninit() if ObjectAddons then ObjectAddons:uninit() end end function update(dt) end function onInteraction(args) return { "OpenCraftingInterface", currentStageData().interactData} end function currentStageData() if self.stageDataList[storage.currentStage].addonConfig then -- merge any data from connected addons local res = copy(self.stageDataList[storage.currentStage]) for _, addon in pairs(self.stageDataList[storage.currentStage].addonConfig.usesAddons or {}) do if ObjectAddons:isConnectedTo(addon.name) then res = util.mergeTable(res, addon.addonData) end end return res else return self.stageDataList[storage.currentStage] end end function upgradeTo(oldStage, newStage) if (newStage <= self.maxUpgradeStage and newStage ~= storage.currentStage) then showUpgradeEffects(oldStage) storage.currentStage = newStage if ObjectAddons then local addonConfig = currentStageData().addonConfig ObjectAddons:init(addonConfig or {}, updateStageData) else updateStageData() end end end function showUpgradeEffects(stageIndex) local stageData = currentStageData() if (stageData.upgradeSoundEffect ~= nil) then animator.playSound(stageData.upgradeSoundEffect) end if (stageData.upgradeParticleEffect ~= nil) then animator.burstParticleEmitter(stageData.upgradeParticleEffect) end end function updateStageData() local stageData = currentStageData() animator.setAnimationState("stage", stageData.animationState) object.setMaterialSpaces(stageData.materialSpaces) for k, v in pairs(stageData.itemSpawnParameters or {}) do object.setConfigParameter(k, v) end end function die() local stageData = currentStageData() stageData.itemSpawnParameters.startingUpgradeStage = storage.currentStage local itemDescriptor = {name = config.getParameter("objectName"), count = 1, parameters = stageData.itemSpawnParameters} world.spawnItem(itemDescriptor, vec2.add(object.position(), {0, 3})) end
This is actually a very interesting concept. Honestly, I would've just added a repair station, but there are many gifted LUA scriptwriters out there who can do so much more. Im glad you found your solution, but hopefully you'll let us know how you did it rather than us having to reverse engineer your work.
Oh yes, certainly. First off, I discovered that the category in json files is purely cosmetic and doesn't actually affect how the object is used at all. It simply controls what the gui says when you hover over the object in your inventory. Second of all, I looked through that lua file again, and discovered this line: "object.setInteractive(true)". I decided to play around with the file and added a line in the script that activates when you upgrade the object: "object.setInteractive(false)". This did the job; the object no longer acts as a crafting station. Unfortunately, when I mine the item and place it again, the upgrade remains, but it reverts to acting like a crafting station, so I'm still messing around with the script to determine how to keep it uninteractable. Depending on how this experiment goes, I might actually expand this into a full-fledged mod where ALL objects deteriorate over time and require repairing, for those who want to have a little more hardcore Starbound experience. Is there anyone who would be interested in such a mod?
That seems less hardcore and more of a simple pain. I mean, sure, it's got to have its purposes and such, but it seems so cumbersome to have such a thing in a SB playthrough.
Hmm, I suppose you're right, that would be more than a bit much as a general mechanic for Starbound. Perhaps for a mission of some sort?
If you could devise some method of making a person move into a house in disrepair that was pre-generated once it’s repaired, that would be a cool sidequest. Definitely less mundane than most of them.