First, some points to be aware of.
- I’m going to assume some knowledge on the part of the reader for this tutorial, so it’s going to read as something of an intermediate topic. I will assume you know how to make a basic mod, including how to add simple items (furniture and decorations are the usual starting points). I will also assume that you understand what a mixinto is.
- Throughout this tutorial, I will use some very specific aliases and nest files in some very specific folders. I do this because they are the same folders that the stonehearth mod uses and they are similar aliases to those used by the stonehearth mod. So if you want to go look for similar examples in the stonehearth mod, it’s pretty easy because it’s all in similar places. You don’t have to make such long aliases or nest your files in the same way, but I feel that it is good practice to do so!
- Anywhere I use CAPITAL LETTERS in a piece of code, that’s your hint to replace that piece of text with your own thing.
- Here are all the code snippets built into an example mod: RESOURCE_MOD.zip (10.5 KB)
. If you put it in your stonehearth mods folder and change the extension to .smod, it should just work.
1. The manifest
I want to talk about this first, because anything you don’t put in the manifest will not be active in the final mod. So it’s really a checklist of things to add.
Our example mod manifest looks like this:
manifest.json
{
"info":
{
"name": "RESOURCE_MOD",
"version": 3
},
"aliases":
{
"resources:RESOURCE" : "file(entities/resources/RESOURCE/RESOURCE_THING)",
"terrain:ui:RESOURCE_block" : "file(entities/terrain/ui/RESOURCE_block)"
},
"mixintos":
{
"stonehearth/data/biome/arctic_generation_data.json" : "file(data/biome/arctic_generation_data.json)",
"stonehearth/data/biome/desert_generation_data.json" : "file(data/biome/desert_generation_data.json)",
"stonehearth/data/biome/temperate_generation_data.json" : "file(data/biome/temperate_generation_data.json)",
"stonehearth/data/terrain/terrain_blocks.json" : "file(data/terrain/terrain_blocks.json)",
"stonehearth/services/server/mining/mining_loot_tables.json" : "file(services/server/mining/mining_loot_tables.json)",
"stonehearth/scenarios/scenario_index.json" : "file(scenarios/scenario_index.json)",
"stonehearth/data/resource_constants.json" : "file(data/resource_constants.json)"
}
}
So what are all these bits for?
-
resources:RESOURCE is the actual item that can be used in recipes by your crafter hearthlings. Maybe it’s a new metal ore, a new stone or some kind of gem.
-
terrain:ui:RESOURCE_block is used to create a tooltip when you click on an vein of your resource in the world. If you don’t want to create veins of your resource in the world, you can leave this out!
-
stonehearth/data/biome/arctic_generation_data.json, stonehearth/data/biome/desert_generation_data.json and stonehearth/data/biome/temperate_generation_data.json are files that describe the way the world is generated depending on the type of map the player wants. Currently only the desert and temperate biomes are playable, but the arctic biome will come eventually (with the viking-type kingdom)! If you want veins of your resource in the world, you must define the color of that vein in each biome. If the color isn’t defined, it will appear as a bright red by default! If you don’t want to create veins of your resource in the world, you can leave this out!
-
stonehearth/data/terrain/terrain_blocks.json is a file that creates the data structures for veins of resources in the world. If you don’t want to create veins of your resource in the world, you can leave this out!
-
stonehearth/services/server/mining/mining_loot_tables.json is the file that determine the rate at which resources are found when mining out the various minable materials in the world. You’ll need this file if you want your resource to be minable in every biome, which means you’ll almost certainly need it in your mod.
-
stonehearth/scenarios/scenario_index.json is a list of a bunch of things that can be found in a world. One possibility is veins of resources. So you’ll only need this is you want veins of your resource in the world. This file itself points at another file, which we’ll get into later.
-
stonehearth/ui/data/constants.json is something you’ll need if you want to create a recipe that uses a generic resource rather than a specific item.
2. Adding a Generic Resource
2.1. The Item
This is the thing that a crafter can use. You’ll need 3 files to create a basic resource item.
- RESOURCE.png is an image of the item that will appear in the inventory screens of the game and will also represent your new resource type in the crafing windows.
- RESOURCE_THING.qb is the model for your resource and is the same as an “iconic” form for any other item. A resource is not placeable or wearable, so you’ll never need a ghost form or a wearable form.
- RESOURCE_THING.json is the basic data of your resource. It will look like this:
RESOURCE_THING.json
{
"mixins": "stonehearth:mixins:item_properties",
"type": "entity",
"components": {
"model_variants": {
"default": {
"models": [
"file(RESOURCE_THING.qb)"
]
}
}
},
"entity_data" : {
"stonehearth:net_worth" : {
"value_in_gold" : 5,
"rarity" : "common",
"shop_info" : {
"buyable" : true,
"sellable" : true,
"shopkeeper_level" : 1,
"shopkeeper_type" : "caravan"
}
},
"stonehearth:catalog": {
"display_name": "i18n(RESOURCE_THING)",
"description": "i18n(A RESOURCE DESCRIPTION.)",
"icon": "file(../RESOURCE.png)",
"is_item": true,
"category": "resources",
"material_tags": "RESOURCE_TYPE resource"
}
}
}
Let’s stop a moment to talk about the tag entry. You want this to be something unique because its going to be checked against later on. So “marble resource” or “amethyst resource”. It can’t be “stone resource” because stonehearth already uses that!
2.2. Adding it to a Loot Table
Next, we need some way for the hearthlings to find it in the world so they can use it. Since we are talking about mining resources, this will need to be through mining. For this, we mixinto the mining_loot_tables.json file.
Here is a basic example, which we’ll expand later on when we talk about veins:
mining_loot_tables.json
{
"mineable_blocks" :
{
"rock" :
{
"entries": {
"default": {
"items": {
"UNIQUE_IDENTIFIER": { "uri" : "RESOURCE_MOD:resources:RESOURCE", "weight" : 0.200 }
}
}
}
}
}
}
What does it mean? The chance of getting anything when you kill, harvest or mine something is given by a loot table. Loot tables work based on something called a weight.
Weights are a handy way to assign a probability of something without assigning a strict probability. A probability is a value between 0 (never happen) and 1 (always happens). So if you are using probability the numbers in your table have to add up to 1 always. So if you add something new or pull something out, you have to calculate your numbers all over again.
Weights are a bit different! A weight merely states how likely something is relative to something else. Say you want A to drop 5 times as often as B. B has an arbitrary weight of 2. Therefore A must have a weight of 10, 5 times as much as B. So currently, we have a total weight of 12. 2/12 times we see B and 10/12 times we see A. What if we want to add item C with a weight of 8 (4 times as common as B)? Now we have a total weight of 20, giving 10/20 times we’ll see A, 2/20 times we’ll see B and 8/20 times we’ll see C. The relative chance of each item dropping is preserved, but the chance of A and B dropping is now less than it was before. This is important.
Anyhow, this bit of data is telling us to add our resource to the “rock” loot table and give it a weight of 0.200. Check the numbers in stonehearth/services/server/mining/mining_loot_tables.json before adjusting this weight. If your number is too low, your resource will not drop much (if at all). If your number is too high, it will outweight every other resource and nothing else will drop!
There are other loot tables in the mining_loot_tables that you can add your resource to if you so desire. Rock is just the most logical one to start with.
The UNIQUE_IDENTIFIER should be replaced with a term that is unique to the resource you are adding. If you use a resource identifier that already exists in the loot table, it will overwrite that entry, causing that thing to no longer drop from that table! You can use the same UNIQUE_IDENTIFIER in different tables though.
NOTE: There exist files in the biomes folder called desert_mining_loot_table.json and temperate_mining_loot_table.json. These files are for any additional mining loot tables you want to add that are specific to that biome type only. Since the method for adding loot tables for these is exactly the same as for the generic file, there is really nothing extra to say about them.
2.3. Making your resource a material
So now we have our item dropping in the world when we mine in rock. How does we create a recipe with it as a requirement?
There are two choices.
- We can specify the exact item by using “URI” : “RESOURCE_MOD:resources:RESOURCE”.
- We can use anything that of a given material type. eg. “material” : “RESOURCE resource”
If we use the first choice, we don’t have to do anything special, but the second option does not happen automatically. You actually have to add some data for it. So why would we go to the effort? Well, maybe you’ve got multiple forms of the resource. Perhaps you’ve added amethysts, diamonds and rubies and they are all tagged “gem resource”. You want to make a recipe that could use amethysts, diamonds or rubies as one of its components. That’s when you use the second option with “material” : “gem resource”!
The information to enable this goes into data/resource_constants.json.
{
"resources" : {
"RESOURCE resource" : {
"name" : "RESOURCE_THING",
"icon" : "RESOURCE_MOD/entities/resources/RESOURCE/RESOURCE.png",
"stacks" : 80,
"default_resource": "RESOURCE_MOD:resources:RESOURCE"
}
}
}
Now, anywhere you use “material” : “RESOURCE resource” as a requirement in a recipe, you’ll see your RESOURCE.png as the icon and the tooltip will show the name RESOURCE_THING.
NOTE: Not yet sure what default_resource does! If anyone knows…
Step 3: Resource Veins
So now you have a resource and it randomly drops when you dig through the rock just like the current metal ores do. Sometimes, you’ll also find motherloads of ore that are called ore veins. This is considerably more work, but it’s quite doable. Let’s take a look at all the bits you need!
3.1: Terrain Blocks
Our first step is to define what the vein will look like in the world. Here we need to mixinto data/terrain/terrain_blocks.json.
terrain_blocks.json
{
"block_types" :
{
"RESOURCE" : { "tag" : 501, "kind" : "RESOURCE_KIND" }
},
"selectable_kinds" :
{
"RESOURCE_KIND" : "RESOURCE_MOD:terrain:ui:RESOURCE_block"
}
}
The “block_types” tag is an organisational element that stonehearth uses to define each block of terrain in the game. The “tag” number must be unique. Check the original file first to make sure you give it a unique tag!
RESOURCE_KIND is the identifying name for the kind of resource. It’s not necessarily the same as the RESOURCE name you’ve used elsewhere.
“selectable_kinds” are all the kinds of terrain in the world that you can click on and see a tooltip. So far, this is only ore veins. You need to use the RESOURCE_KIND you just defined in block_types and then point at the file that is going to describe your resource.
So next we need to create that descriptive file!
RESOURCE_block.json
{
"mixins": "stonehearth/entities/terrain/ui/ore_block",
"entity_data": {
"stonehearth:catalog": {
"display_name": "RESOURCE vein",
"description": "Provides RESOURCE when mined."
}
}
}
As you can see, it has a mixin from the ore_block file, but we don’t need to worry about that. The important stuff is the display_name and description, which provides the tooltip text you see when you click on the ore vein.
The last part of defining the look of a vein is to define its colour. To do this, we are going to have to get stuck into the biome definition files. Currently, there are three of these: arctic_generation_data.json, desert_generation_data.json and temperat_generation_datae.json. Only desert_generation_data.json and temperate_generation_data.json are being used right now, but the artic one will be coming in a future alpha, so might as well be ready for them. In each of these files, there is a “palette” definition with a “spring” definition nested inside. For now, seasons aren’t implemented, so we only need to add something to the spring definition for each biome. I’ll just show one file, but you can just cut-and-paste to each file anyway, with the possible exception of the colour.
temperate.json
{
"palettes" :
{
"spring" :
{
"RESOURCE" : "#DEDEDE"
}
}
}
The RESOURCE here is the block_type you defined before. The information #DEDEDE is an RGB color in hexadecimal notation. Do pick your own color to give it a unique look! If you are lucky, you might be able to get away with using the same color for every biome. If you aren’t so lucky, a color that is plainly visible in one biome may blend into the colors of another biome. The color is defined per biome and per season so that you can fix problems like that on a case-by-case basis.
3.2. Defining the vein
We’ve pretty well defined what the vein looks like, now we can talk about how to make the vein appear in the world.
Veins are a kind of “scenario”, which is some things that can appear in the world in a specific place. Our first step is to mixinto scenarios/scenario_index.json.
scenario_index.json
{
"static" :
{
"scenarios" :
[
"file(static/terrain/RESOURCE_vein/RESOURCE_vein.json)"
]
}
}
This is basically a manifest file for scenarios with it’s own categories. Ore veins don’t move, so they go in the static category.
Now we can add the scenario definition that tells the game what the vein should be like in its own file.
RESOURCE_vein.json
{
"mixins" : "/stonehearth/scenarios/static/terrain/ore_vein/ore_vein.json",
"name" : "RESOURCE_vein",
"kind" : "RESOURCE",
"weight" : 200,
"data" :
{
"num_veins_min" : 5,
"num_veins_max" : 10,
"vein_length_min" : 20,
"vein_length_max" : 40,
"vein_radius" : 3,
"mother_lode_radius_min" : 5,
"mother_lode_radius_max" : 7
}
}
Again, RESOURCE must be the same as defined previously. This is the block_type defined in terrain_blocks.json.
The weight is the chance of this particular scenario spawning in the world. Common ore veins like iron and copper have a weight of 75, while gold is only 40. A large number like 200 or 500 is only appropriate for testing purposes. Make sure to adjust this number down after you are sure everything works!
Some of the entries in “data” affect how big your ore vein will be. Normally a vein is between vein_length_min and vein_length_max voxels long (horizontally) and vein_radius blocks high (should be 1-4). mother_lode_radius_min and mother_lode_radius_max determine how wide the widest part of the vein is.
3.3. Loot tables, part 2
Finally, we are ready to define the things you can get when you mine a block of your ore vein. We need to mixinto mining_loot_tables.json some more. Your mixinto file from part 2.2 above will now look like this:
mining_loot_tables.json
{
"mineable_blocks" :
{
"rock" :
{
"entries": {
"default": {
"items": {
"ore": { "uri" : "RESOURCE_MOD:resources:RESOURCE", "weight" : 0.200 }
}
}
}
},
"RESOURCE_KIND" :
{
"entries": {
"default": {
"num_rolls": 1,
"items": {
"none": { "uri": "", "weight": 6 },
"ore": { "uri": "RESOURCE_MOD:resources:RESOURCE", "weight": 1 }
}
}
}
}
}
}
This extra data tells the game to check the RESOURCE_KIND loot table when mining out one of your resource vein blocks. It then defines the loot table.
As you can see, I have “num_rolls” set to 1, which means the game checks once to see what item drops. Maybe you want to make it rain resources? You could set it to 10 and the game would check the loot table 10 times for each time your hearthlings mine out a block.
We also have two “items” listed in the RESOURCE_KIND loot table. The second one is your resource as expected. But what is the first? Because there is no item listed, it’s the chance that no item drops. So in the example, 6 out of 7 times, you’ll mine a block and nothing comes out. 1 out of 7 times you’ll get your resource. If you like, you can add more things to your resource vein loot table. Maybe it’s a gem vein and you have a chance to get a amethyst, diamond, emerald or nothing. You’d need four entries then.