Last updated: December 10th, 2018. Latest version here.

Static scenarios

Static scenarios are static elements that appear on the map and are created at world generation time. They can be shown by default, or hidden until the hearthlings clear the fog of war. They're separate from the biome files.

They are managed in the static_scenario_service.lua file.

These are different types of static scenarios we can create with just data (you can also create your own types of static scenario, using custom scripts):

Dynamic scenarios were deprecated a long time ago in favor of the game master's encounter system.

The starting tutorial that was made for the Ascendancy kingdom was also implemented using scenarios, most of its data is inside stonehearth/data/tutorial.

Inside scenario_index.json we can find the scenarios that are applied to the game. We'll also find the categories that we can use for each scenario, so we can create our own category by adding it to this section via a mixinto:

  "categories" : {
     "terrain" : {
        "density" : 12,
        "priority" : 0,
        "location_type" : "surface",
        "activation_type" : "immediate"

Each category has these fields:

  • "density" -- scenarios are weighted by their volume so that a density of 1 means every cell is occupied. A 10x10 scenario takes up the same volume as 100 1x1 scenarios. For their densities to be equal, the 10x10 scenario should be selected 100x less frequently.
  • "priority" -- so that some scenarios can spawn before other ones, they get ordered first by priority, then by area, then by weight.
  • "location_type" -- either "surface" or "underground".
  • "activation_type" -- "immediate" will make the scenario appear during world generation, "revealed" will make it appear when the hearthlings clear the fog of war where it is located.

For the landmark scenarios, we have other categories:

  "terrain_feature_common" : {
     "density" : 100,
     "max_count": [2,2,3,3,3,4,4],
     "prevents_categories_in_same_tile": ["terrain_feature_common", "terrain_feature_rare"],
     "priority" : "random",
     "location_type" : "surface",
     "activation_type" : "immediate"

They have a couple more properties:

  • "density", "location_type" and "activation_type" are the same than for the categories above.

  • "priority" is "random", they are treated in a separate set from those that have a numerical priority, and will be chosen randomly.

  • "max_count" is an array of numbers. A random number will be chosen from it to represent how many landmarks of this category to spawn on a map.

    In this example there's three 3's, and two 2's and 4's, which means 3 is more likely to be chosen, so there will be more times when 3 landmarks of this category will spawn in a map, other times there will be only 2, or 4.

  • "prevents_categories_in_same_tile" is an array of other categories of scenarios that we don't want to appear in the same tile as this category.

Custom static scenario types

Scenarios can be implemented using a JSON file to hold the data, and a Lua script. Then we can reuse that JSON file as a mixin to implement different scenarios of that type (just like we do for ore veins, ruins, critter nests and landmarks).

The concrete JSON files will then be added to the scenario index, and the game will know how to spawn them.

If we want to create our own custom static scenario type, our JSON file will need to have these fields:

  "name" : "my_custom_scenario",
  "size" : {
     "width" : 16,
     "length" : 16
  "weight" : 10,
  "unique" : false,
  "script" : "file(my_custom_scenario.lua)",
  "data" : {
     "entity_footprint_length" : 1,
     "quantity" : {
        "min" : 2,
        "max" : 5

Then, our custom script should look like this:

  local MyCustomScenario = class()

  function MyCustomScenario:__init()

  function MyCustomScenario:initialize(properties, context, services)
     -- Here we can retrieve the data from the JSON's "data" block like this:
     local data =

     -- Here goes our custom code. We can use the parameter called services
     -- to call functions from
     -- stonehearth/services/server/static_scenario/scenario_modder_services.lua

  return MyCustomScenario

We can require any additional classes or Lua files, but if they're from the stonehearth mod, we need to prefix them by stonehearth.. For example, to require the same files than in the qb_to_terrain.lua script, we'd write this:

  local landmark_lib = require 'stonehearth.lib.landmark.landmark_lib'
  local Point3 = _radiant.csg.Point3

And after that we'd declare the class for our scenario.