Starbound

Starbound

Not enough ratings
Modding: Shops & Merchants Guide
By Ceterai
If you're looking to create a merchant tenant/npc/object (like a vending machine) and set their shop pool, check out this guide.
WEBSITE[ceterai.github.io] | SUPPORT ME[buymeacoffee.com]
   
Award
Favorite
Favorited
Unfavorite
Introduction
This guide provides information about how to:
  • turn a regular NPC into a merchant and configure them
  • configure a shop pool for that NPC
  • make a tenant for that NPC
Or, if you're looking to make an object merchant (a static shop, like a vending machine, Infinity Express, or Terramart):
  • turn a regular object into a shop and configure it
Enjoy!
Shop Table
Merchant NPCs select their goods randomly from categories listed in a ".config" JSON file, similar to loot tables:
{ <shop category name> : [ [ 0, // minimal environment level requirement for the list below to be considered [ { "item" : { "name" : "humantier2head" } }, // minimal syntax { "item" : { "name" : "humantier2head" }, "rarity" : 0.9 }, // how rare is this option { "item" : { "name" : "humantier2head", "parameters" : { "colorIndex" : 4 } }, "rarity" : 0.5 }, { "item" : { "name" : "humantier2head" } } // no rarity means always present ], 0.5, // minimal level is 1, so for player's ship the list above will be used, not below [ { "item" : { "name" : "humantier2head", "parameters" : { "colorIndex" : 1 } }, "rarity" : 0.5 } ], 3.5, // minimal level is 4, so for level 3 planets the list above will be used [ { "item" : { "name" : "humantier2head", "parameters" : { "colorIndex" : 1 } }, "rarity" : 0.5 } ] ] ], "basicmerchant" : [ // category name example [0, [ { "item" : { "name" : "torch" }, "rarity" : 0.3 }, { "item" : { "name" : "flare" }, "rarity" : 0.3 }, { "item" : { "name" : "climbingrope" }, "rarity" : 0.3 }, { "item" : { "name" : "redstim" }, "rarity" : 0.05 }, { "item" : { "name" : "bluestim" }, "rarity" : 0.05 }, { "item" : { "name" : "yellowstim" }, "rarity" : 0.05 }, { "item" : { "name" : "paperplane" }, "rarity" : 0.0001 }, { "item" : { "name" : "beachball" }, "rarity" : 0.0001 }, { "item" : { "name" : "bowlingball" }, "rarity" : 0.0003 }, { "item" : { "name" : "bowlingpin" }, "rarity" : 0.0003 }, { "item" : { "name" : "firework" }, "rarity" : 0.0002 }, { "item" : { "name" : "fireworkblue" }, "rarity" : 0.0002 }, { "item" : { "name" : "fireworkgreen" }, "rarity" : 0.0002 }, { "item" : { "name" : "noveltybanana" }, "rarity" : 0.00005 } ]] ] }
Note! If you set a "parameters" key in an option, even if it's empty, the game will add the environment level as a "level" parameter on top of it.
Because of this, setting a "level" manually through parameters is practically useless in shop tables.
So, if you're wondering why your item suddenly has incorrect level in the shop as opposed to other items, this is most likely due to it having "parameters" in the shop table.
Merchant NPC
Creating an NPC is pretty easy, especially if your NPC is based on another NPC that's close to your needs.
Unlike most things in Starbound, NPCs can inherit config of a parent NPC set in the "base" parameter.
That said, let's pretend like our base NPC isn't a merchant at all, just so I could show you all the parameters needed to turn them into one, and to also configure them properly.

NPCs are defined in ".npc" JSON files, usually located in the "/npcs/" folder.

This is the rough structure we want:
{ "type" : <NPC ID>, "baseType" : "base", // using the most basic NPC as base, you can use whichever fits you "persistent" : true, "damageTeamType" : "friendly", // a friendly NPC that doesn't despawn "dropPools" : ["basicTreasure"], // list of loot tables to use as drops - ["empty"] for no drops "scriptConfig" : { "behavior" : "merchant", // important "behaviorConfig" : { "noticePlayersRadius" : 20, // how far the player can be for the merchant to start touting "hostileDamageTeam" : { "type" : "enemy", "team" : 1 } // enemies }, "questGenerator" : { "pools" : ["common", "merchant"], // possible quest groups "enableParticipation" : true // whether this NPC will participate in other quests }, "merchant" : { "waitTime" : 40, // wait near the shop "storeRadius" : 16, // shop area around the spawn point of the NPC "poolsFile" : "/npcs/merchantpools.config", // a shop table file to choose categories from, see previous section to know how these work "categories" : { // usually the minimum is to have the "default" to use for all species "default" : ["genericarmour", "basicmerchant"], // default list of categories "apex" : ["genericarmour", "basicmerchant", "apexfurniture", "randomguns", "randomswords", "apexarmour", "apexingredients" ], // species-specific list of categories "avian" : ["genericarmour", "basicmerchant", "avianfurniture", "randomguns", "randomswords", "avianarmour", "avianingredients" ] }, "buyFactorRange" : [0.9, 1.2], // a multiplier is randomly chosen between these 2 values and is applied to all items this merchant will sell "sellFactorRange" : [0.2, 0.2], // a multiplier is randomly chosen between these 2 values and is applied to all items this merchant will buy from you "numItems" : 10 // number of items in the merchant's assortment }, "dialog" : { // phrase pools, let's use default merchant phrases for now "merchant" : { "start" : "/dialog/merchant.config:merchantStart", // opened UI "end" : "/dialog/merchant.config:merchantEnd", // closed UI "follow" : "/dialog/merchant.config:follow", // far from shop, let's go to the shop "welcome" : "/dialog/merchant.config:welcome", // arrived at the shop "tout" : "/dialog/merchant.config:tout" // hey, I sell cool stuff! }, "tenant" : { "grumbles" : { // merchant variations of tenant grumbles "tagCriteria" : "/dialog/merchant.config:tagCriteria", "enclosedArea" : "/dialog/merchant.config:enclosedArea", "otherDeed" : "/dialog/merchant.config:otherDeed", "severe" : "/dialog/merchant.config:severe", "final" : "/dialog/merchant.config:final" }, "arrivedHome" : { // merchant variations of "I've arrived!" and "Thank you, here's a gift!" "beacon" : "/dialog/merchant.config:beacon", "rent" : "/dialog/merchant.config:rent" } } } }, "items" : {...} // items your NPC will wear. Refer to vanilla NPCs for examples
Note: if you need a list of all parameters, I'd recommend checking out vanilla NPCs, primarily the base one - "/npcs/base.npc"
Merchant Tenant
So... you've created a merchant NPC in the previous section, and you want them to be a tenant.
I might make a separate guide on this later, but for now - read the instructions below.

Tenants are defined in ".tenant" JSON files (usually) in the "/tenants/" folder.
These are just colony deed conditions that, if met, will spawn an NPC or a list of NPCs of certain species, with optional parameter/level overrides.

This is what the syntax looks like:
{ "name": "chef_random", // tenant definition ID, must be unique, doesn't have to match NPC's ID "priority": 3, // in case conditions for multiple different tenants are met at the same time "colonyTagCriteria": { // tenant conditions - keys are colony tags, values are amount of blocks "light": 1, // default minimal condition for all tenants "door": 1, // default minimal condition for all tenants "cooking": 8 }, "tenants": [ // though a list, usually it only has 1 entry, otherwise it'll spawn > than 1 NPC { "spawn": "npc", "species": ["human", "apex"], // can either be a string (just one species), or a list "type": <NPC ID>, // NPC type (ID), for example "chefmerchanttenant" "overrides": { } // optional parameters that will override default config of this NPC } ], "rent": { "periodRange": [1200.0, 1800.0], // time in seconds until next rent is selected randomly between these 2 values after previous rent has been collected. "pool": <loot table ID> // a pool from which items are chosen as a rent payment, usually for merchnt tenants the value is "merchantGift" } }
If you want to learn more about loot tables/treasure pools, here's a helpful guide:
https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=3377225094
Merchant Object
If you don't really want an NPC merchant and just want an object that can sell things, this section is for you.

First of all, please note that there are 2 types of object merchants:
  • Pixel Shop - regular shop that sells & buys items for pixels. Examples: Infinity Express, Terramart, various vending machines.
  • Crafting Shop - a "shop" where items can be bought (not sold), in exchange for other items. Essentially just a crafting table. Examples: 2 Stop Teleshop, Treasured Trophies.
There's also Frögg Furnishing, which is unique in that it rotates its store assortment overtime.
Similar to it is the Biggy's Reputable Weaponry, which also has rotation, but selects multiple items from the list, instead of selecting a list of items.

Now, all of these are configured in the object's ".object" JSON file along with all the other parameters.

Pixel Shop
A regular pixel shop. As opposed to merchant NPCs, the store's inventory is defined directly in the shop's ".object" file.
Examples: Infinity Express, Terramart, various vending machines.
"interactAction" : "OpenMerchantInterface", // don't forget this "interactData" : { "config" : "/interface/windowconfig/merchant.config", // don't forget this "paneLayoutOverride" : { "windowtitle" : { "title" : " Infinity Express", // override default title with yours "subtitle" : " ^#b9b5b2;Fuel, snacks and sundries", // a short description "icon" : { "file" : <shop icon path (optional)> } } }, "buyFactor" : 5.0, // general multiplier applied to all items sold by this shop "sellFactor" : 0.2, // general multiplier applied to all items you sell to this shop "items" : [ // this is where you should list your items for selling { "item" : "flashlight" }, // syntax is { "item" : <your itemName> } { "item" : { "name" : "bandage" } }, // as you can see there's no rarity/weight { "item" : "tungstenbar", "prerequisiteQuest" : "human_mission1" }, // quest condition { "item" : "soda", "prerequisiteShipLevel" : 3 }, // min ship level condition { "item" : "soda", "exclusiveQuests" : ["shipupgrade1"] }, // current quest condition ..., { "item" : "soda" } ] },

Crafting Shop
Basically a crafting table that presents itself as a shop. Due to its nature, its assortment/inventory is defined by recipes. All recipes should have whatever is listed in "interactData.filter" in their "groups" list in order to appear here.
Examples: 2 Stop Teleshop, Treasured Trophies.
"interactAction" : "OpenCraftingInterface", // different from the one used by pixel shops "interactData" : { "config" : "/interface/windowconfig/craftingmerchant.config", // also different "paneLayoutOverride" : { "windowtitle" : { "title" : <shop name>, "subtitle" : " ^#b9b5b2;<shop tagline>", "icon" : { "file" : <shop icon path (optional)> } }, "imgPlayerMoneyIcon" : { "visible" : false }, // optional, hides your pixels "lblPlayerMoney" : { "visible" : false } // optional, hides your pixels }, "filter" : ["teleshop"] // list of recipe tags to filter the recipes by },
To know more about recipes and what are recipe groups, check out this guide:
https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=2020613420
Rotation Shop
A pixel shop that regularly presents a different pre-set collection of items from its inventory.
Examples: Frögg Furnishing.
"interactData" : { "config" : "/interface/windowconfig/craftingfurniturestore.config", "paneLayoutOverride" : { "windowtitle" : { "title" : <shop name>, "subtitle" : " ^#b9b5b2;<shop tagline>", "icon" : { "file" : <shop icon path (optional)> } } }, "filter" : [] // should be empty }, "scripts" : ["/objects/outpost/frogfurnishing/frogfurnishing.lua"], // important - path to custom logic "scriptDelta" : 0, "rotationTime" : 86400, // time of feature set availability in seconds "storeInventory" : { // items that are present no matter what "deeds" : ["colonymanual-codex", "colonydeed"], "furniture" : ["lamppost1", "lamppost3", ..., "outdoorstool"], // rotated items "featured" : [ ["earthmodel", ..., "venusmodel"], [...], ..., [...] ] }

Random Shop
A pixel shop that regularly presents a random assortment of n items from its inventory.
Examples: Biggy's Reputable Weaponry.
"interactAction" : "OpenMerchantInterface", "interactData" : { "config" : "/interface/windowconfig/craftingmerchant.config", "paneLayoutOverride" : { "windowtitle" : { "title" : <shop name>, "subtitle" : " ^#b9b5b2;<shop tagline>", "icon" : { "file" : <shop icon path (optional)> } } }, "filter" : [] // should be empty }, "scripts" : ["/objects/outpost/penguinweaponshop/penguinweaponshop.lua"], // custom logic "scriptDelta" : 0, "rotationTime" : 86400, // time between re-generations in seconds "selectCount" : 2, // how many items are selected at once "inventoryPool" : ["neochakram", ..., "vinefist"] // items to choose from
Conclusion
This is all I have to share on this topic. Let me know if there's anything I'm missing! ^^
Helpful Resources
More about merchants:
https://starbounder.org/Merchant

More about merchant tenants:
https://starbounder.org/Tenant#Merchants