Modding Discussion Trying to turn one object into another object

Discussion in 'Starbound Modding' started by Fruiteyes, Dec 2, 2016.

  1. Fruiteyes

    Fruiteyes Phantasmal Quasar

    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:


    [​IMG]
    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:
    [​IMG]


    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
    
     
    Last edited: Dec 5, 2016
    LegoMaster3650 likes this.
  2. IHart

    IHart Scruffy Nerf-Herder

    share the solution you used? we are curious
     
  3. LegoMaster3650

    LegoMaster3650 Void-Bound Voyager

    Wow, this would be an amazing thing to know how to do! Please make a tutorial for this!
     
  4. Mioure

    Mioure Scruffy Nerf-Herder

    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.
     
  5. Fruiteyes

    Fruiteyes Phantasmal Quasar

    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?
     
    AmazonValkyrie and Inf_Wolf14 like this.
  6. Pint

    Pint Space Spelunker

    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.
     
  7. Fruiteyes

    Fruiteyes Phantasmal Quasar

    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?
     
  8. Pint

    Pint Space Spelunker

    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.
     

Share This Page