Generic encounters

Let's take a look at the available encounter types and their associated properties. Their controllers can be found in stonehearth/services/server/game_master/controllers/encounters.

Wait encounters

Wait

An encounter that waits for the specified length of game time before triggering its out edges.

  • "encounter_type" : "wait"

  • "wait_info" : {}

    • "duration" -- a time expression representing how much in-game time we want to wait.
    • "game_mode_tuning" -- optional field. A boolean for enabling tuning overrides for the "duration" parameter of this encounter. You can check an example in the "encounter_tuning_overrides" section from stonehearth/data/game_mode/hard/hard.json (the field is called `"delay" there). In this case, the modifier would be applied when the player chooses hard mode.
    • "destroy_on_trigger" -- optional field. A boolean to destroy this node after the out edge is triggered.
    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter / timer and resumes it once the player reconnects).

Wait for time of day

An encounter that waits until a given game time of day before triggering its out edges.

  • "encounter_type" : "wait_for_time_of_day"

  • "wait_for_time_of_day_info" : {}

    • "time" -- the in-game time of day with an optional random element. E.g.: "15:30" means '3:30 PM'. "5:00+1h30m" means 'between 5:00 AM and 6:30 AM'.
    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter / timer and resumes it once the player reconnects).

Wait for event

An encounter that waits for an event on an entity (or entitites) before triggering its out edges.

  • "encounter_type" : "wait_for_event"

  • "wait_for_event_info" : {}

    • "source" -- object where the event will be listened to. Usually an entity from a previous encounter that has been registered in the shared context. Example: "wolf_pack_raid.wolves".

      This property can also be an array, e.g.:

         [
            "spawn_enemy_entities.wolf_skeleton",
            "spawn_enemy_entities.skeletons",
            "spawn_enemy_entities.skeleton_giant"
         ]
      

      The out edge will trigger once the event has been triggered for all of the sources. Notice that these entries can also refer to more than one entity too (e.g. in a previous encounter we create a random number of skeletons and store a reference to each of them in "spawn_enemy_entities.skeletons").

    • "event" -- name of the event to wait for. Example: "stonehearth:kill_event".

    • "repeatable" -- optional field. A boolean, false by default. If true, continues to listen and trigger out edges until this node is destroyed.

    • "trigger_on_each" -- optional field. A boolean, false by default. If true, and "source" refers to multiple entities, triggers the out edge when any entry has the event triggered, instead of when all sources have had the event triggered. Normally used with "repeatable" : true.

Wait for net worth

An encounter that waits for the player to reach a specified net worth before triggering its out edges.

  • "encounter_type" : "wait_for_net_worth"

  • "wait_for_net_worth_info" : {}

    • "threshold" -- when net worth is higher than the threshold, the out edge will be triggered. It can be a number (no decimals) or a range, in which case we'll write it like this:

      "threshold": {
         "min": 3700,
         "max": 4000
      }
      

      A random number will be picked in that range, and we'll compare the net worth with it.

    • "interval" -- optional field ("1h" by default). A time expression for how often to check the net worth value to attempt to trigger the out edge. Checking less frequently is better for performance.

    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter / timer and resumes it once the player reconnects).

Wait for requirements met

An encounter that waits until a set of requirements is satisfied before triggering its out edges.

  • "encounter_type" : "wait_for_requirements_met"

  • "wait_for_requirements_met_info" : {}

    • "requirements" : {} -- the list of requirements. For defining them, use the same structure and fields than inside the "can_start" tests. E.g.:

      "requirements" : {
         "city_tier": {
            "type": "deny_if_less_than",
            "item": "city_tier",
            "value": 2
         },
         "kingdom_check": {
            "type": "deny_if_not",
            "item": "kingdom",
            "value": "stonehearth:kingdoms:ascendancy"
         }
      }
      
    • "recheck_delay" -- optional field, a time expression. In-game time to wait between attempts to trigger the out egde, "1h" by default.

    • "max_checks" -- optional field. Maximum amount of times to check. I.e. if we set this field to 5, the sixth time that we try to check the requirements the node will get destroyed.

    • "cancellation_event" -- optional field. Name of an event that will be listened on the population faction of the player. If the event gets triggered while this node is still active, the node will get destroyed.

    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter / timer and resumes it once the player reconnects).

Gate encounters

Generator

A generator that triggers edges after a delay, optionally repeating in a loop.

  • "encounter_type" : "generator"

  • "generator_info" : {}

    • "delay" -- a time expression. In-game time to wait before triggering the "spawn_edge". The delay timer will be restarted each time that the edge is triggered.

    • "spawn_edge" -- name of the edge to spawn after the delay (for example, "city_raid"). Can also refer to more than one edge (using the same syntax than for the value of out edges).

    • "source_entity" -- optional field. Name of an object registered in the context (e.g. "goblin_raiding_camp_1.boss"). If the source entity is destroyed or doesn't exist, this encounter will stop spawning edges.

    • "min_spawns" -- optional field. Minimum number of times that we want the generator to trigger the edges (minimum 1).

    • "max_spawns" -- optional field. Maximum number of times that we want the generator to trigger the edges (minimum 1).

      If we specify both "min_spawns" and "max_spawns", a random number of times will be chosen between them and used as the spawn limit.

      If we don't include any of them, the generator will keep spawning edges indefinitely (or until the source entity is destroyed, if we defined that field).

      iconIf this generator encounter also has an out edge, it will be triggered when the maximum number of spawns is met (the minimum if we only defined min, or the random number if we included both).

    • "game_mode_tuning" -- optional field. A boolean for enabling tuning overrides for the "delay" parameter of this encounter. You can check an example in the "encounter_tuning_overrides" section from stonehearth/data/game_mode/hard/hard.json. In this case, the modifier would be applied when the player chooses hard mode.

    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter / timer and resumes it once the player reconnects).

Item threshold

An encounter that waits until a threshold is satisfied before triggering its out edges. The threshold will be compared with the item count from the player's storages, as long as those items match certain materials or URIs.

  • "encounter_type" : "item_threshold"

  • "item_threshold_info" : {}

    • "threshold" -- the amount to compare. It can also be a range, like this:

      "threshold" {
         "min": 800,
         "max": 1200
      }
      

      In this case a random number between "min" and "max" will be chosen to compare.

    • "check" -- either "less_than" or "greater_than". The condition to compare the threshold with. Internally they're treated as 'less or equal than' and 'greater or equal than'.

    • "materials" : [] -- an array of material tags. If we define this field, the encounter will trigger its out edge when the threshold is met for the items that have all the material tags from this array.

    • "uris" : [] -- an array of URIs. The items will match for the threshold if their URI is in this array.

    We must define either the "materials" array or the "uris" array. Defining both will only take the "uris" one into account.

Flag encounters

Counter

An encounter that counts the number of times it runs and saves this information in the user-specified ctx.ctx_registration_variable.

If it manages to run X times, it produces its success out edge. Otherwise, it produces its failure out edge. Both are specified in the out_edges field in the "counter_info".

  • "encounter_type" : "counter"

  • "counter_info": {}

    • "out_edges" : {} -- contains the out edges that will trigger. E.g.:

      "out_edges": {
         "fail": "wait_for_next_shakedown",
         "success": "unlock_red_token_recipe"
      }
      

      Usually the "fail" out edge eventually leads back to an ancestor of this node, so that it can run again, but there are also other ways to run the same node again.

    • "times" -- count up to this amount before triggering the "success" edge. Before then, triggers the "fail" edge.

    • "ctx_registration_variable" -- a name for the variable to store the current count in. E.g.: "blue_tier_shakedown_success_counter".

    • "optional_reference_entity" -- optional field, a reference to an entity registered previously in the shared context (e.g. "create_blue_tier_camp.entities.loot_chest"). The encounter only increases the count if the reference entity still exists and is the same one as last time. If it doesn't exist, then the encounter does nothing. If it exists, but is a different entity than the one stored in context from last time, the counter starts again.

Set counters

Updates the values of campaign-wide counters which are used for gating encounters via the "counter" can_start check.

  • "encounter_type" : "set_counters"

  • "set_counters_info" : {}

    • "counters" : {} -- one or more key-value pairs where the key is the name of a counter that we want to create or reuse, and the value is either a number or a formula to evaluate. The formula is a string containing any Lua expression, where 'x' is the counter's current value (defaults to 0). For example:

      "counters" : {
         "foo": 42,
         "bar": "x / 2 + 1",
         "quux": "stonehearth.calendar:get_seconds_since_last_midnight()"
      }
      

icon Don't confuse these counters with the "counter" encounter. They have different purposes.

Utility encounters

Destroy entity

An encounter that destroys specific entities.

  • "encounter_type" : "destroy_entity"

  • "destroy_entity_info" : {}

    • "target_entities" : [] -- an array containing the registration paths (e.g. "golem_raid.golems") of the entities that should be destroyed.

    • "effect" -- optional field. URI of an effect that the entities will play when they get destroyed (e.g.: "stonehearth:effects:poof_effect:grey").

    • "random_delay" : {} -- optional field. A range ("min" and "max" values) of milliseconds. A random amount will be chosen between them and the entities will despawn after waiting for it. This is used so that the entities don't disappear all at the same time, and so that they don't start the effect (if specified) all at the same time. Normally we use a tiny value, less than a second.

    • "continue_always" -- optional field (a boolean). When true, triggers next encounter even if didn't destroy anything. When false, will not continue if didn't destroy anything.

      Usually you'll want to set this to true if the entities might have been destroyed by other means before this encounter gets to run (for example, mobs from ambient threats that the hearthlings might have already killed).

    • "destroy_all_registered_entities" -- optional field. A boolean, when true, the encounter destroys all entities in ctx.entity_registration_paths instead of the ones specified in "target_entities" (so you can use this field instead of that one if you want everything destroyed). Useful for cleaning up mobs after a while, to save computer resources as new entities spawn in the map.

    • "script" -- optional field. URI for a script to run right before destroying the entities. The script must have a "start" function at least. For example:

      local GoblinCampDepartsScript = class()
      
      -- When the camp departs, no matter how the player interacted with
      -- these goblins, set amenity for all goblins back to hostile.
      
      function GoblinCampDepartsScript:start(ctx)
         stonehearth.player:set_neutral_to_everyone('goblins', false)
      end
      
      return GoblinCampDepartsScript
      

      We can access the encounter's context using the ctx argument. Remember that if you want to use an alias for your script instead of a path, you must add it under "controllers" in the manifest.

Script

An encounter that does nothing but run the associated script (which is created as a controller).

  • "encounter_type" : "script"

  • "script_info" : {}

    • "script" -- the URI of the script to run. Similar to the example script above, it must have a start(ctx, data) function. The ctx argument will have the context of the node, and the data argument will contain the data from the "data" field in the encounter's JSON file. Remember that if you want to use an alias for your script instead of a path, you must add it under "controllers" in the manifest.

    • "data" : {} -- optional field. The data that will be passed to our custom script.

    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter and resumes it once the player reconnects).

      icon If you don't set "continue_on_disconnect" to true, you might need to implement suspend() and continue() functions in your custom script, so that the game knows if it has to stop some timer, resume it later, etc. They will be called when the player disconnects / reconnects.

Dialog encounters

Bulletin

An encounter that displays a notification bulletin.

  • "encounter_type" : "bulletin"

  • "bulletin_info" : {}

    • "type" -- either "info", "alert" or "quest". This changes the appearance of the bulletin in the game. If the type is "alert", it will be shown separately from the normal bulletins and won't be hidden automatically when another bulletin is shown. New alerts will show on top of older ones.
    • "title" -- a localized text for the bulletin. The bulletin will disappear when the player clicks on it. If you want some other message to appear in a window after this, take a look at the dialog tree encounter.
    • "sticky" -- optional field (a boolean, false by default). Sticky bulletin notifications stay up in the UI until the user addresses them. Non-sticky ones will fade out after some seconds, but will still be accesible in the bulletin list.
    • "zoom_to_entity" -- optional field. Reference to a context registration path. When the user clicks on the bulletin, the camera will focus on this entity if it exists.
    • "send_to_all_players" -- optional field (a boolean, false by default). Use when you want the bulletin to appear for all the players. This is normally not wanted, since the campaigns run independently for each player, but it can be useful sometimes (for example, this is used in the Titan campaign since it affects a large portion of the map, often messing with other players' towns).
    • "active_duration" -- optional field (a time expression. If we specify this field, the bulletin will be automatically removed after this duration even when the player hasn't interacted with it. Useful to prevent cluttering the bulletin list with notifications that might not be relevant anymore after a while.

Dialog Tree

An encounter that displays a dialog tree whose choices eventually lead to potentially different out edges.

  • "encounter_type" : "dialog_tree"

  • "dialog_tree_info" : {}

    • "start_node" -- key of the dialog node with which we want to start (e.g. "msg1").

    • "source_entity" -- optional field. A reference to an object from another node (e.g. "goblin_raiding_camp_1.boss"). The dialog tree will only start if this source entity exists.

    • "i18n_data" : {} -- optional field. A dictionary for setting i18n var data for the dialogs. Can be a reference to ctx paths or literal values. E.g.:

        "i18n_data" : {
           "boss_display_name" : "Emma",
           "town_name" : "town_name"
        }
      

      In the en.json file we'd use them like this, for example:

        "msg01" : "The enemy called [str(i18n_data.boss_display_name)] appears",
        "msg02" : "They came with a goblin called [name(i18n_data.goblin)]."
      

      The difference between [str()] and [name()] is that [name()] is used when we want to reference the name of an entity that's been registered in the context (an entity that has a custom name - such as hearthlings, monsters and NPCs). In that case we don't need to add it to "i18n_data".

      There are some encounters that will add variables to the context, we can use those as values in our "i18n_data" too (for example, the town's name is already registered in town_name since many dialogs wish to call on it).

    • "script" -- optional field. The URI of a script that will get to run before the dialog starts (remember that if you want to use an alias for your script instead of the path, you must add it under "controllers" in the manifest).

      Similar to the example above, it must have a start(ctx, info) function (we'll pass it the context and all the info accessible under "dialog_tree_info" from the encounter's JSON file). An example would be initializing custom i18n data before the dialog runs, e.g.:

       "i18n_data" : {
          "town_serial_number": "town_serial_number",
          "english_town_ordinal_suffix": "english_town_ordinal_suffix"
       }
      

      We declared the above data in our encounter's JSON file, but their value isn't initialized anywhere. So we create and reference the following script which will register the values for those variables in the context:

       local TownProgressionI18NDataScript = class()
      
       function TownProgressionI18NDataScript:start(ctx)
          ctx.town_serial_number = stonehearth.town:get_town(ctx.player_id)
                                                   :get_town_serial_number()
          ctx.english_town_ordinal_suffix = english_number_ordinal_suffix(ctx.town_serial_number)
       end
      
       function english_number_ordinal_suffix(number)
         local n = ""..number
         local ordinal, digit = {"st", "nd", "rd"}, string.sub(n, -1)
         if tonumber(digit) > 0 and tonumber(digit) <= 3 and
              string.sub(n,-2) ~= 11 and string.sub(n,-2) ~= 12 and
              string.sub(n,-2) ~= 13 then
           return ordinal[tonumber(digit)]
         else
           return "th"
         end
       end
      
        return TownProgressionI18NDataScript
      

      Then we can use [str(i18n_data.town_serial_number)] in the texts of our dialog tree.

    • "choose_ctx_portrait" : [] -- optional field. An array with URIs of portraits for the dialog. One of these provided options will be chosen and can be referenced by this and later dialogs that set "use_ctx_portrait" and have nodes with a portrait field.

    • "use_ctx_portrait" -- optional field (a boolean). Whether to use a (currently or previously) "chosen_ctx_portrait". This way we can choose a random portrait on each gameplay for variety, but keeping it for the duration of the quest.

    • "nodes" : {} -- the nodes of the dialog. Each node is an object with a custom identifying key (try to use meaningful names to keep your data organized). Inside each node, we have the "bulletin" : {} field with the following properties:

      • "title" -- a localized title for the notification. We need it for all the nodes, since each dialog will also be an entry in the bulletin list, even if the notification only pops up for the first one. The bulletin type will always be "quest" for this encounter type.
      • "dialog_title" -- a localized title for the dialog. Will appear at the top of the dialog window. It is mandatory, but if you don't want to have it you can define it as an empty string.
      • "portrait" -- optional field. URI of a portrait for the dialog. If you registered a portrait in the same encounter or in a previous encounter, and have set "use_ctx_portrait" to true, then you can set the portrait to an empty string (in some of the existing encounters you'll see "$ctx" for this too).

      This will ensure that the portrait is shown and that it reuses the one that was saved in the context. Note that using a registered portrait will make it so all dialog nodes from the encounter have the same portrait, as long as the field exists in them. You won't be able to change specific ones to other portraits if you reuse the portrait.

      • "portrait_offset" -- optional field. Number of pixels to offset the portrait from the top.

      • "message" -- a localized text for the message of the current node. It can also be an array of localized texts, that way one will be chosen at random. You can include i18n_data in the localized text, as well as some HTML tags to give it a bit of format.

      • "choices" : {} -- one or more choices for the player to advance the dialog to the next node. Their keys are localized texts for the buttons, but WITHOUT the "i18n()" wrapping them. their values are objects and will vary. For example:

         "choices" : {
            "my_mod_namespace:campaigns.abc.encounters.dialog_1.msg1.choice_00": {
               "next_node": "msg2"
            },
            "my_mod_namespace:campaigns.abc.encounters.dialog_1.msg1.choice_01": {
               "next_node": "msg4"
            },
            "my_mod_namespace:campaigns.abc.encounters.dialog_1.msg1.choice_02": {
               "out_edge": "dialog_ends"
            }
         }
        

        We can have either "next_node", pointing to the key of another node of the dialog, or "out_edge", which will finish the dialog and trigger the specified out egde.

        icon Notice that for this encounter type we often don't have an out edge defined, because the out edge is specified in the dialog choices, and more than one choice can point to the same out edge.

Shop

An encounter that displays a shop menu with a given set of items for sale.

  • encounter_type" : "shop"

  • "shop_info" : {}

    • "name" -- a localized name for the shop. Will appear on top of the shop window.
    • "title" -- a localized text for the shop notification.
    • "inventory" : {} -- the contents of the shop. They will match the specified set of filters (rarities, materials, URIs...). You can see a longer explanation about how to set them up here.

Delivery quest

An encounter that represents a persistent quest notification that can be completed or abandoned.

  • "encounter_type" : "delivery_quest"

  • "delivery_quest_info" : {}

    • "title" -- a localized text for the bulletin notification.

    • "dialog_title" -- a localized text for the quest dialog, will appear at the top of the window.

    • "text" -- optional field. A localized text to show above the list of requirements.

    • "abandon_out_edge" -- optional field. Out edge that will be triggered if the player abandons this quest (in the town progression quests, this points to a previous encounter, so that the player can choose this quest again if they want to).

    • "requirements" : [] -- an array of objects with requirements to fulfill the quest (player can complete the quest whenever they want, as long as these requirements are met. They can also abandon the quest at any given moment if they need to).

      Each requirement will have a "type" field and one or more additional fields that depend on it (they're indented below for readability). Here are the possible values:

      • "type" : "give_item" -- deliver N items of the specific URI.

        • "uri" -- URI of the item.
        • "count" -- amount of items to deliver.
        • "keep_items" -- optional field (a boolean). When true, the items won't be removed from the player's inventory on quest completion.
      • "type" : "give_material" -- deliver N items that are tagged with the given material.

        • "material" -- material tag that the items must have to fulfill this requirement.
        • "count" -- amount of items to deliver.
        • "keep_items" -- optional field (a boolean). When true, the items won't be removed from the player's inventory on quest completion.
      • "type" : "job_level" -- have a hearthling of the given job at a given minimum level.

        • "uri" -- alias of the job.
        • "level" -- a citizen must be at least this level in the given job in order to fulfill the requirement.
      • "type" : "happiness" -- have N citizens at a given minimum happiness level.

        • "min_value" -- a number representing the minimum happiness to fulfill the requirement. Remember that happiness goes from 1 to 100.
        • "min_citizens" -- a number representing how many citizens must be at least that happy to fulfill the requirement. Instead of a number, you can also use "all", to represent all citizens regardless of how many of them there are.
      • "type" : "gold" -- have N gold coins (current, spent, or earned).

        • "subtype" -- either "give", "have", "spent" or "earned". If the subtype is "give", the gold will be subtracted from the player's inventory on quest completion. The "spent" and "earned" types refer to gold obtained by buying and selling in shops.
        • "count" -- the required amount of gold.
      • "type" : "have_item_quality" -- have N deployed or stored items of a given minimum quality.

        • "quality" -- a number representing the item quality: 1 for standard quality, 2 for fine quality, 3 for excellent quality and 4 for masterwork quality (mind that this last quality is only unlocked in one branch of the town progression quests).
        • "count" -- the amount of items that must have at least the given quality.
      • "type" : "net_worth" -- have a given minimum net worth.

        • "value" -- the minimum net worth to have.
      • "type" : "placed_item" -- have a given item placed in the world.

        • "uri" -- URI of the item.

Collection quest

An encounter that shows a dialog asking for items.

  • "encounter_type" : "collection_quest"

  • "collection_quest_info" : {}

    • "out_edges" : {} -- contains 3 fields ("refuse", "fail" and "success"), each pointing to the out edge to trigger depending on the results of the quest.

      iconNote that usually we don't add an out edge to this encounter's JSON file, since it will trigger one of these depending on the player's choice.

    • "script" -- URI of the controller of a script that will determine which items to ask for (e.g.: "stonehearth:game_master:script:collection_quest_shakedown"). If you create your own, make sure to add it under "controllers" in your manifest. We'll pass the data under "collection_quest_info" to the script on creation. The script must have a get_tribute_demand function that returns an object (Lua table) containing URIs of items pointing to four fields: uri, count, icon and display_name. Take a look at how it's implemented in collection_quest_shakedown.lua.

    • "filler_material" : {} -- optional field. Contains a map of URIs of biomes pointing to URIs of resources. Depending on the biome, a different resource will be chosen as a filler material for the request. This is used in the "stonehearth:game_master:script:collection_quest_shakedown" script, so you may want to add your own custom data if you don't reuse it.

    • "skip_return_trip" -- optional field (a boolean). When true, the encounter is a simple item request so the "collection_due" dialog will be shown directly.

      icon There's a known issue that when using this option the player can confirm the dialog even when not having all of the items (in which case only the available items will be removed from inventory). This means that the "fail" out edge can't be triggered, only the "success" and "refuse" ones can. If you want to use this option, you may want to use the delivery quest encounter instead.

    • "source_entity" -- optional field. A reference to a context registration path. The encounter won't start if this entity doesn't exist, and will be halted if the entity dies while the quest is active.

    • "duration" -- a time expression for how long to wait before collecting the requested items.

    • "dialog_view" -- optional field, if it's "portrait" the same view than for showing the demands will be used. Otherwise, you can use the name of a custom UI view. This dialog view will be used only for the introduction dialog.

    • "i18n_data" -- optional field. Same than for the dialog tree encounter.

    • "nodes" : {} -- a list of nodes for the dialog. Each node is a key containing several properties. The keys must have the following names: "introduction", "shakedown", "shakedown_refused", "collection_progress", "collection_due", "collection_failed", "collection_success", "revenge".

      Only the "collection_due", "collection_failed" and "collection_success" nodes are mandatory, the rest are optional.

      Assuming all are defined, the order in which they'll appear is: "introduction", "shakedown", then "collection_progress" if the player accepts, or "shakedown_refused" if the player declines, in which case the "refuse" out edge will trigger and the "revenge" dialog will appear.

      If the player accepted, after waiting for the "duration" the "collection_due" dialog will appear, then if they have the requested items and accept to give them, the items will be removed from inventory, the "collection_success" dialog will appear and the "success" out edge will be triggered. If the player didn't have the requested items or refused, the "collection_failed" dialog will appear instead, the "fail" out edge will trigger and the "revenge" dialog will appear. It will also run the revenge(requested_items, info) function from the associated script. The second parameter will contain the revenge bulletin data, inventory tracking data and revenge node data.

      Each of these dialog nodes contains a "bulletin" field with the following properties:

      • "title" -- a localized title for the bulletin notification.
      • "dialog_title" -- a localized title for the dialog window (mandatory for this encounter, but leave it as an empty string if you don't want it).
      • "portrait" -- path to a portrait image for the dialog (mandatory for this encounter).
      • "message" -- a localized text or an array of localized texts (in which case, a random one will be chosen). The message to show in the dialog. They can use variables from the "i18n_data" field.

Reward encounters

Donation dialog

An encounter that generates items and give them to the player via a dialog.

  • "encounter_type" : "donation_dialog"

  • "donation_dialog_info" : {}

    • "loot_table" -- a loot table with entries describing the items to donate to the player. Can be omitted if you only want to donate gold.

    • "donation_gold" -- optional field. Amount of gold to donate (no decimals). If we registered donation_gold in the context in a previous encounter, we can omit this field and the registered variable will be used instead.

    • "expiration_timeout" -- optional field (a time expression). If we specify this field, the dialog will be automatically removed after this duration even when the player hasn't interacted with it. Useful to prevent cluttering the bulletin list with notifications that might not be relevant anymore after a while.

    • "choose_ctx_portrait" : [] -- optional field. Same than for the dialog tree encounter.

    • "use_ctx_portrait" -- optional field. Same than for the dialog tree encounter.

    • "i18n_data" : {} -- optional field. Same than for the dialog tree encounter.

    • "nodes": {} -- contains the "simple_message" field, inside which there's the "bulletin" field with the following properties:

      • "title" -- same than for the dialog tree encounter.

      • "dialog_title" -- same than for the dialog tree encounter.

      • "portrait" -- optional field. Same than for the dialog tree encounter.

      • "message" -- same than for the dialog tree encounter.

      • "choices" : {} -- same than for the dialog tree encounter, EXCEPT that they can only contain a "result" key with a value of either "accept" or "reject". If the user clicks on the option that rejects, they won't get the items.

        The out edge is specified at the encounter level, like in most of the other encounter types.

Donation

An encounter that generates items and drops them by the player's camp standard. If you want to have also some dialog for informing the player, you might want to use the donation dialog encounter instead.

  • "encounter_type" : "donation"

  • "donation_info" : {}

    • "loot_table" -- a loot table with entries describing the items to donate to the player.
    • "container" -- optional field. URI of an entity to act as a loot box (will spawn and have the loot command on it, spawning the items from the loot table when the player clicks on the command).
    • "ctx_entity_registration_path" -- an optional field. Name for a context path in which to reference the spawned items (either the container, or the items if we have no container).

Unlock recipe

An encounter that unlocks recipes for the player.

  • "encounter_type" : "unlock_recipe"

  • "unlock_recipe_info" : {}

    • "job" -- URI of the job that contains the recipes to unlock. Remember that they must exist in the recipe index of this crafter and they must have "manual_unlock" : true.
    • "recipe_key" : [] -- can be just one string or an array of strings if we want to unlock more than one recipe. Each key must correspond to a recipe, in the form of "crafting_category:recipe_key", as taken from the corresponding recipes index (e.g.: "furniture:amberstone_table" for the mason).
    • "bulletin_title" -- a localized text for the bulletin notification.

Town progression encounters

Town upgrade choice

An encounter that shows a dialog to choose a town upgrade and optionally the town's name.

  • "encounter_type" : "town_upgrade_choice"

  • "town_upgrade_choice_info" : {}

    • "includes_town_naming" -- optional field. A boolean to determine whether to show a text box to let the player change the name of their town.

    • "choices" : {} -- list of choices to upgrade the town's banner/hearth/etc. Each choice is a custom identifier containing the following properties:

      • "name" -- a localized name for the banner/hearth/etc type.

      • "description" -- a localized description of the associated town bonus.

      • "icon" -- path to an image of the corresponding banner/hearth/etc.

      • "sort_order" -- an ordinal to sort the different choices in the UI.

      • "out_edge" -- the out edge to trigger when the player chooses this option. It should eventually lead to an encounter of type town upgrade, which will grant the bonus mentioned in the description to the player's town.

        iconNotice that usually we don't add an out edge to this encounter's JSON file, since it will trigger different ones depending on the player's choice.

Town upgrade

An encounter that grants a town bonus and/or replaces the banner or hearth. The hearthlings (and optionally some NPCs) will gather around the item to upgrade, it will be changed (granting the town bonus), the town tier will increase, and then the hearthlings and NPCs will celebrate for a while (using the "celebration" track from their sound constants). NPCs will depart and despawn once the celebration ends.

Most of the fields are optional, so this can also be used to issue a celebration around an item.

  • "encounter_type" : "town_upgrade"

  • "town_upgrade_info" : {}

    • "tier_achieved" -- optional field. A number representing the tier to which we're upgrading the player's town.

    • "celebration_duration" -- a time expression to represent the duration of the celebration. Make sure to define this field.

    • "old_facility_uri" -- URI of the item that we're upgrading (banner, hearth, etc). The upgrade and celebration will only start once this item is placed down (e.g. in case this encounter was triggered while the item was being moved). Hearthlings will congregate around it.

      If no old facility is defined, the town's hearth will be chosen. If it doesn't exist, the town's banner will be used instead.

      If the old facility is not a unique entity, we'll choose a random one from the player's inventory, preferring one that's already placed in the world.

    • "new_facility_uri" -- optional field. URI of the item that will replace the old banner/hearth/etc.

    • "facility_upgrade_effect" -- URI of a VFX to play when upgrading the old facility. Usually covers it at some point to hide the sudden change from the old one to the new one.

    • "town_bonus" -- optional field. URI of the controller that has the concerning town bonus. Remember to add it under "controllers" in your manifest. An example of town bonus that does nothing:

      local MyTownBonus = class()
      
      function MyTownBonus:initialize()
         self._sv.player_id = nil
         self._sv.display_name = 'i18n(my_mod:data.gm.campaigns.town_upgrades.hearth_choice.bonus.name)'
         self._sv.description = 'i18n(my_mod:data.gm.campaigns.town_upgrades.hearth_choice.bonus.description)'
      end
      
      function MyTownBonus:create(player_id)
         self._sv.player_id = player_id
      end
      
      return MyTownBonus
      

      The functions above will ensure that the bonus appears in the Bonuses tab of the town overview UI. You can see more examples of controllers for bonuses in stonehearth/data/town_bonuses. In some parts of the game we check for specific bonuses like this:

      local town = stonehearth.town:get_town(self._sv._entity:get_player_id())
      town:get_town_bonus('stonehearth:town_bonus:strength')
      

      This allows to execute some code depending on the current town bonus, and we can also call functions from the town bonus controller, e.g.:

      local town = stonehearth.town:get_town(session.player_id)
      local glory_bonus = town:get_town_bonus('stonehearth:town_bonus:glory')
      if glory_bonus then
         return glory_bonus:spawn_next_wave(source_entity)
      end
      return false
      
    • "finish_event" -- optional field. Name of the event that will be triggered on the player's population once the celebration ends.

    • "conversation_subjects" : [] -- optional field. An array of URIs of subject matters to inject for the celebration. They will all have a positive sentiment. For instance, we inject the "stonehearth:subjects:town_status", "stonehearth:food:cake" and "stonehearth:banner:strength" subjects for the upgrade to strength banner in the vanilla game. Hearthlings will have a chance to talk about them during the celebration.

    • "thought" -- optional field. URI of the thought to inject to all hearthlings, relevant to the current upgrade (e.g. "stonehearth:thoughts:town:progression:outpost").

    • "has_fireworks" -- optional field. A boolean to determine whether to run the "stonehearth:effects:fireworks" effect or not. Mind that this effect will be played from the new facility.

    • "dialog" : {} -- optional field. Data for a dialog that will pop up right before congregating for the celebration. It contains the following fields:

      • "title" -- a localized text for the bulletin notification.

      • "dialog_title" -- a localized text for the title of the dialog, will appear at the top of the window.

      • "tier_title" -- a localized text for the tier achieved (outpost, settlement, etc).

      • "reward_message" -- a localized text for the first part of the proclamation message (e.g.: "By unanimous agreement of the citizens, we declare:").

      • "reward_message_ctd" -- a localized text for the second part of the proclamation message (e.g.: "to be an outpost on its way to be a safe haven for all.").

        The reward/proclamation message will appear in the middle of the window. It's divided in two parts because the town's name will appear between them.

      • "achievements" : [] -- an array of objects. It's a list describing the achievements associated with the town tier / bonus, shown at the bottom of the dialog. Each entry contains the following properties:

        • "id" -- a unique identifier for this entry (e.g.: "strength_bonus_1").
        • "name" -- a localized short text describing the achievement ("Random Daily Buffs", "Tier 2 BGM", etc).
        • "icon" -- path to an icon to show in the dialog for this achievement. In the vanilla game it's a ribbon, but you can use different ones for each reward.
        • "track" -- URI of a sound track to play when the achievement appears in the UI (achievements will appear one by one, as if unlocking).
    • "npcs" : [] -- optional field. An array of NPCs to spawn for the celebration. Each entry is an object containing these properties:

      • "faction" -- name of the population faction of the NPC (e.g.: "human_npcs").
      • "role" -- role of the NPC inside the population data (e.g: "herald_harold").
      • "gender" -- gender of the NPC (e.g.: "male").

      For more about populations, refer to this page and this other page. Normally NPCs will have "amenity_to_strangers" : "neutral", so that enemies can't attack them. Their faction can't be hostile towards the player's faction at the moment of the celebration, otherwise they won't spawn.

City tier achieved

An encounter that shows a dialog celebrating the player's ascendance to a new tier of city.

This encounter type was used before celebrations were implemented in the game. So in practice, it does more or less the same than the town upgrade encounter. Here, a notification will open a normal dialog message first, and when the player proceeds, the city tier success dialog will appear.

  • "encounter_type" : "city_tier_achieved"

  • "city_tier_achieved_info" : {}

    • "tier_achieved" -- a number representing the town tier achieved.

    • "event_to_broadcast" -- name of the event that will be triggered on the player's population after increasing the town tier.

    • "title" -- a localized text for the notification bulletin.

    • "speaker_name" -- a localized text for the first dialog.

    • "speaker_portrait" -- path to a portrait for the first dialog.

    • "message" -- a localized text for the first dialog.

    • "accept" -- a localized text for the button of the first dialog.

    • "dialog_title" -- a localized text for the title of the dialog, will appear at the top of the window.

    • "tier_title" -- a localized text for the tier achieved (outpost, settlement, etc).

    • "reward_message" -- a localized text for the first part of the proclamation message (e.g.: "By decree of Princess Dania of the Ascendancy, we recognize:").

    • "reward_message_ctd" -- a localized text for the second part of the proclamation message (e.g.: "For acts of incredible valor in combat. The town is hereby eligible for:").

      The reward/proclamation message will appear in the middle of the window. It's divided in two parts because the town's name will appear between them.

    • "achievements" : [] -- same than for the town upgrade encounter type.

City tier quest

An encounter that shows the requirements needed to get to the next level of city tier. The notification persists in the bulletin list until one of the sets is satisfied. Button to check requirements, if met, will call the herald back immediately and triggers new out edge. If the herald automatically detects that the set is satisfied, the notification goes away.

This is the old implementation of the tier upgrade quest, where 3 possible paths/requirement sets are presented in the same window, so that the player can try to fulfill any of them at any given moment.

  • "encounter_type" : "city_tier_quest"

  • "city_tier_quest_info" : {}

    • "target_tier" -- a number representing the tier to upgrade to. It's just informative, the tier is granted in a city tier achieved or town upgrade encounter.

    • "finish_event" -- optional field. Name of the event that we'll listen to in order to remove the bulletin (will be triggered on the player's population). The bulletin will also be removed and the encounter node destroyed once the quest is completed.

    • "title" -- a localized text for the bulletin notification.

    • "dialog_title" -- a localized title for the dialog. Will appear at the top of the window.

    • "text" -- a localized text for the dialog. Will appear at the top of the dialog.

    • "summon_text" -- a localized text for the button to complete the quest (e.g.: "Summon Herald"). It will be enabled once one or more of the requirement sets are fulfilled.

    • "satisfaction_requirements" : {} -- a list of requirement sets to fulfill. Each one is a custom key referencing a set of requirements. Each entry contains the following properties:

      • "id" -- an identifier for this quest path (e.g.: "town_military_req").

      • "title" -- a localized text for this requirement set to display in the UI.

      • "out_edge" -- out edge to trigger if this requirement set is fulfilled.

      • "requirements" : {} -- a list of requirements. Each entry in the list will be a custom key containing the following properties:

        • "id" -- a custom identifier for this requirement (e.g.: "military_statue").

        • "type" -- for this encounter type, there are only 2 possible types of requirements: either "placed_item" or "net_worth".

        • "uri" / "value" -- if the type was "placed_item", we'll have an "uri" field pointing to the URI of the item that must be placed; if it was "net_worth", a "value" field for the amount of net worth to have.

          Mind that if you use the "placed_item" type, you should name the entry "place_statue". This will ensure that the icon in the UI corresponds to the required item.

Citizen encounters

Add citizen

Adds a new citizen to the town, either of the player's population or of another race/faction. They will spawn close to the town and will walk to the banner first.

icon Mind that once added to the player's town, you won't be able to retrieve the original population of the citizen by code. They will be considered to have the same population/faction than the player's town, even if their appearance is different (e.g. rabbits, orcs).

  • "encounter_type" : "add_citizen"

  • "add_citizen_info" : {}

    • "population" -- optional field. URI of the kingdom of the new citizen (e.g.: "stonehearth:kingdoms:amberstone"). If it's omitted, the same kingdom than the player's town will be used.

    • "role" -- optional field. Role from the population data to use. If omitted, the "default" role will be used.

    • "gender" -- optional field. A gender for the new citizen. If omitted, a random gender will be used. Genders are specified in stonehearth/data/constants.json, and match entries inside the different roles.

    • "job" -- URI of the job that the new citizen will have by default. Although this is considered an optional field, make sure to set it up so that the new citizen has a proper outfit and can be promoted to other jobs. It's not guaranteed that a default job will be used.

    • "level" -- optional field. Default level for the new citizen on the specified job.

    • "allowed_jobs" : [] -- optional field. An array containing URIs of jobs. This restricts the jobs that the new citizen can be promoted to. Useful when the citizen is from another faction that doesn't have outfits or animations for some of the jobs from the player's population job index.

    • "equipment" : [] -- optional field. An array of URIs of equipment pieces that will be automatically equipped to the new citizen (mind the equipment roles regarding the job).

    • "notification_title" -- optional field (no notification will be shown if this field is omitted). A localized text for the notification bulletin. When the player clicks on the bulletin, the camera will focus on the new citizen. You can use i18n_data.citizen_custom_name, i18n_data.citizen_display_name and i18n_data.town_name in the localized text if you want to.

    • "attribute_distribution_override" : {} -- optional field. If included, it will override the default stats from the population for this citizen.

      • "allocated_points" : {} -- contains "min" and "max" properties. A random number of points will be chosen between them.
      • "point_limits" : {} -- contains entries whose key is the name of a main stat ("mind", "body", "spirit") and whose values are also "min" and "max", to establish how much points can be given to a certain stat. Stats influence the rest of attributes.

Reembarkation

An encounter to generate an embarkation crew composed of up to 3 citizens and up to 10 items to reuse in a new game (if the player chooses a town progression item, it will carry the town bonus with it).

It will also include unlocked crops (for the "stonehearth:jobs:farmer" job) and unlocked crafting recipes from any crafting job, but these have conditions to be unlocked in new games (if you choose a reembarkation crew from a different kingdom, the recipes must already exist in the current kingdom's recipe indexes and the job URI of the crafter must also match, otherwise they can't be unlocked).

The citizens will keep their job, level and equipment, but beware that embarking with high level combat units might increase the combat difficulty on early game.

The reembarkation can be postponed (kept in the bulletin list or not), but once the player has clicked on "Depart", the crew will be saved to a file and a celebration around the banner will begin. When the celebration ends the selected citizens will depart the town forever and the selected items will also disappear from inventory. Players can always go back to a previous savefile if they don't want those citizens to depart.

  • "encounter_type" : "reembarkation"

  • "reembarkation_info" : {}

    • "reject_out_edge" -- out edge that will be triggered if the player postpones the dialog ("Maybe Next Month" option). In the vanilla game this is set up so that the current encounter node is destroyed, and the reembarkation generator keeps running in the background with a delay of 30 in-game days.

Dispatch quest

An encounter that represents a quest to dispatch a citizen out of the town for some duration.

  • "encounter_type" : "dispatch_quest"

  • "dispatch_quest_info" : {}

    • "title" -- a localized text for the bulletin notification.

    • "dialog_title" -- a localized text for the dialog. Will appear at the top of the window.

    • "text" -- a localized text for the dialog, describing which type of citizen to select for dispatching. Will appear above the list of citizens.

    • "return_delay" -- a time expression to represent how much time it will pass before the citizen returns.

    • "buff_on_return" -- optional field. URI of a buff to grant the dispatched citizen once they return.

    • "thought_on_return" -- optional field. URI of a thought to grant the dispatched citizen once they return.

    • "xp_gained" -- optional field. Amount of experience to grant the dispatched citizen once they return.

    • "abandon_out_edge" -- out edge to trigger when the player explicitely abandons this quest.

    • "ctx_registration_variable" -- optional field. Name of a context registration path to store the dispatched citizens.

    • "requirements" : [] -- an array of citizen requirements, one entry per citizen you want to dispatch. Each entry is an object with the following properties:

      • "job" -- URI of the required job. The hearthling must have this as their current job in order to be eligible.

      • "job_level" -- optional field. The minimum job level for the hearthling to be eligible.

        In some existing encounters of this type, you might see that instead of a requirements array there's a "required_job" and a "required_job_level" fields. These are deprecated because they only allow to choose one hearthling, so the "requirements" array is preferred.

        If no requirements are defined, the player will be able to choose one citizen of whatever job.

Raid encounters

Create camp

An encounter that creates an NPC camp made up of mobs and / or items.

  • "encounter_type" : "create_camp"

  • "create_camp_info" : {}

    • "npc_player_id" -- (required field) a player or NPC faction name (the "kingdom_id" of a population file). Can be an empty string (will be considered unspecified).

    • "amenity_with_player" -- optional field (either "hostile" or "neutral"). We'll set the amenity of the mobs from this camp towards the player. Don't use at the same time than the "neutral_to_everyone" field.

    • "neutral_to_everyone" -- optional field (a boolean). When true, nobody will be able to attack the mobs from this camp, they'll be neutral to every other faction. Remember to unset this later otherwise mobs from the specified faction will still be neutral in future encounters.

    • "ctx_entity_registration_path" -- optional field (e.g.: "goblin_raiding_camp_1"). A name for a context registration path. We'll store references to the entities from "citizens" in it (actually inside <your_custom_ctx_path>.citizens).

    • "use_previous_enemy_location" -- optional field. A boolean to spawn the camp on the previously registered enemy location (ctx.enemy_location).

    • "use_entity_location" -- optional field. A context registration path referencing a placed entity. The camp will spawn where the entity is.

    • "belongs_to_player" -- optional field. A boolean for the camp pieces to belong to the player (by default they'll belong to the faction from "npc_player_id").

    • "radius" -- (required field) radius of the camp in number of blocks.

    • "keep_grass" -- optional field (a boolean). By default the layer of grass will be removed if the camp spawns on top of grass, creating a depression in the terrain. Use this field to keep the grass. In any case, the camp will destroy any entities where it spawns (like trees or anything that doesn't belong to the player).

    • "spawn_range" : {} -- (required field). Contains "min" and "max" properties to determine the range around the town's perimeter (in number of blocks) where to spawn the camp.

    • "script" -- optional field. URI of a script to run after spawning the camp and registering all its entities, for further customization. Must have a start(ctx, info) function, it will receive the context and the info inside "create_camp_info". If you make a custom one, remember to add it under "controllers" in your manifest.

    • "combat_bulletin" : {} -- optional field. Contains a "title" field with a localized text, to show it as a notification bulletin when the players citizens run into an enemy from this camp.

    • "searcher_delay" -- optional field. A time expression. If the camp couldn't find a suitable place to spawn (enough space in the given range around the town), we'll wait for this duration and try to search for a place to spawn again ("3d" by default). This is a safety measure so that the encounter doesn't stall.

    • "on_searcher_failure" : {} -- optionald field. Contains "retry" (a boolean for retrying or a number for a maximum number of retries) or a "destroy_root_node" (pointing to the in edge of the node from which we want to destroy). Used if the searcher failed to find a place to spawn the camp.

    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter / timer and resumes it once the player reconnects).

      For this encounter type, if the camp has already spawned it will continue to exist regardless of this option. But if the timer to find a place was running when the player disconnected, it will stop trying and resume once the player comes back (so that the camp is only allowed to spawn when the player is connected).

    • "landmark_data" : {} -- optional field. Contains properties like "brush" and "landmark_block_types" to generate a landmark for the camp. Check stonehearth/lib/landmark/landmark_lib.lua for the possible fields (options for the create_cube_as_terrain and create_qb_as_terrain functions).

    • "pieces" : {} -- the pieces for the camp (required field). Each entry is a custom identifier with the following properties:

      • "entity_uri" -- URI of an item. Instead of this field, we can use an "info" field pointing to a JSON file describing the camp piece (allows for using more properties). Check the stonehearth/data/gm/campaigns/goblin_war/arcs/trigger/raidcamp/encounters/create_camp folder for examples.
      • "position" : {} -- contains "x" and "y" coordinates relative to the camp's center seen from above (the camp's center would be at (0,0)).
      • "npc_player_id" -- optional field. Name of the faction that will own the camp piece.
      • "rotation" -- optional field. Rotation for the camp piece in degrees.
      • "movable" -- optional field (a boolean). Whether this item should have the move / undeploy commands to allow the player to move it.
    • "citizens" : {} -- optional field. List of living entities such as monsters or NPCs to spawn in the camp. Each entry is a custom identifier containing the following properties:

      • "from_population" : {} -- using this field means that we want to spawn entities defined in the "npc_player_id" population file. These are the properties inside "from_population":

        • "role" -- the role within the population that we want this entity to be.

        • "gender" -- optional field. The gender for the entities in this entry. If we don't have this field, a random gender will be chosen based on the ones in the population.base_genders array from stonehearth/data/constants.json.

        • "location" : {} -- optional field. Contains "x" / "y" / "z" properties to place this entity inside the camp.

        • "range" -- optional field. A number representing blocks / world units, to randomize the spawn location of the entity in a range around "location".

        • "min" -- optional field. Minimum amount of entities to spawn for this entry.

        • "max" -- optional field. Maximum amount of entities to spawn for this entry. A random number of entities between "min" and "max" will spawn. If they're not specified, they'll default to 1.

        • "scale_with_run" : {} -- optional field. Used to increase the number of entities that we spawn based on the number of times that this encounter has been triggered. Contains these properties (when defined, "min" and "max" will be modified by them, or just by the number of runs if you leave the field empty):

          • "encounter_cap" -- optional field. When scaling by the number of runs, this will serve as a cap so that the number doesn't get too high.
          • "scale_factor" -- optional field. When included, "min" and "max" be multiplied (and rounded) by this value to the power of the number of times the encounter has run minus one.

        Instead of the "from_population" field, we can also use "from_ctx", pointing to an entity previously registered in the context. The properties below are outside of "from_population":

      • "attributes" : {} -- optional field. Contains pairs of attribute name/value to apply to the entity.

      • "combat_leash_range" -- optional field. A number higher than 0 for the leash range. This is how many blocks are the entities allowed to walk away from their spawn area (prevents them from being kited too far from their home location).

      • "equipment" : {} -- optional field. Contains custom identifiers pointing to either URIs or arrays of URIs of equipment pieces. They will be equipped to all the entities of this entry. If an array is used, a random equipment piece will be chosen from it, so if you want multiple pieces to be equipped you have to add them as separate entries with URIs.

      • "equipment_scale" -- optional field. A number representing the scale for the equipment pieces (so that big monsters don't use tiny weapons).

      • "job" -- optional field. URI of the job to promote this entry's entities to.

      • "loot_drops" : {} -- optional field. A loot table with loot to apply to this entry's entities.

      • "render_info" : {} -- optional field. Contains a "color_map" and / or a "material_maps" field pointing to URIs of a color / material map, to apply to this entry's entities.

      • "scale" -- optional field. Scale to apply to this entry's entities.

      • "tuning" -- optional field. URI of a monster tuning file (e.g.: "stonehearth:monster_tuning:goblins:default") to apply to the entities (can have more additional properties and it's a good way to reuse the info between encounters). You can find the existing tuning files in stonehearth/data/monster_tuning. They're JSON files, so if you create a new one you might want to add an alias for it in your manifest.

      • "unit_info" : {} -- optional field. Contains properties from the unit_info component to apply to the entities ("display_name", "custom_name" and "description").

      The "citizens" will be stored as an array in the context, so we can reference them later individually by index, for example "create_scout_camp.citizens.wolf_cage.tame_wolf[1]" (remember that Lua indexes start at 1).

    • "boss" : {} -- optional field. Same properties than for the "from_population" / "from_ctx" fields from the "citizens" list. Represents the boss of this camp. If you specified a "ctx_entity_registration_path", it will get registered under it as boss and its custom name and display name will get registered in the context as boss_custom_name and boss_display_name (so that you can use them in dialogs). If it refers to several entities, only one of them will be registered as the boss.

Create mission

An encounter that starts a mission undertaken by NPCs. E.g. wandering around or pillaging.

  • "encounter_type" : "create_mission"

  • "create_mission_info" : {}

    • "spawn_range" : {} -- optional field. Has "min" and "max" properties to determine the range around the town's perimeter (in number of blocks) where we want to spawn the mobs.

    • "continue_on_disconnect" -- optional field. A boolean for continuing to run this node when a player (client) disconnects from a multiplayer game. It's false by default (pauses this encounter / timer and resumes it once the player reconnects).

      For this encounter type, if the mobs have already spawned they will continue to exist regardless of this option. But if the timer to find a spawn location was running when the player disconnected, it will stop trying and resume once the player comes back.

    • "use_previous_enemy_location" -- optional field (a boolean). When true, the mobs will spawn at the previous enemy location (a camp, etc).

    • "on_searcher_failure" : {} -- optional field. Contains "retry" (a boolean for retrying) or "destroy_tree" : {} ( with "destroy_root" : true and "root" : "in_edge_of_encounter_node_to_destroy" properties). Used if the searcher failed to find a place to spawn the mobs.

    • "mission" : {} -- required field. The fields inside will vary depending on the type of mission, we'll start with the common ones:

      • "ctx_entity_registration_path" -- optional field (e.g.: "goblin_raiding_camp_1"). A name for a context registration path. We'll store references to the entities from "members" in it.

      • "combat_bulletin" : {} -- optional field. Contains a "title" property for a localized text to show a notification bulletin when a hearthling runs into an enemy from this mission. This field can also be called "sighted_bulletin" : {}.

      • "npc_player_id" -- the faction name for the NPCs of this mission. If it was defined in a previous encounter, this field might be omitted.

      • "members" : {} -- required field. Same properties than in the create camp encounter.

      • "offset" : {} -- required field. Contains "x", "y", "z" properties, to spawn the mobs at an offset from the spawn location.

      • "use_wait_entity_location" -- optional field (a boolean). When true, the mobs will spawn at the previous registered enemy location.

      • "raid_timeout_minutes" -- optional field (4300 by default, which is around 3 days). The mobs will depart/despawn (if they have the raid timeout observer) after this amount of in-game minutes.

      • "raid_timeout_variance_minutes" -- optional field (0 by default). The mobs will despawn sometime between "raid_timeout_minutes" and "raid_timeout_minutes" plus "raid_timeout_variance_minutes" (creates a time expression internally using the numerical values from those fields as minutes).

      • "role" -- the mission type, must be one of the following:

        • "raid_stockpiles" -- the mobs will steal items from player's stockpiles and/or destroy them (it depends on their AI actions, e.g.: goblin workers and thieves know how to steal but marauders will only destroy stuff).

          For this mission type we can have an additional field: "require_free_stockpile_space". It's an optional boolean. When true, the mobs won't raid the stockpiles if they don't have enough space in their own stockpiles. If the player doesn't have stockpiles, mobs will just run to the town and hopefully find something to attack in their way, although they might end up just wandering aimlessly.

        • "spawn_enemies" -- simply spawn some enemies. For this mission type, we can have an additional field: "spawn_effect". It's optional (URI of an effect to play when the enemies spawn).

        • "raid_crops" -- this mission won't start if the player doesn't have farms. This is used for critters to come and destroy the player's crops. For this mission type there are no additional properties.

        • "pillage" -- enemies will spawn and go to some place to attack. If they couldn't reach the destination after 3 in game hours, we'll try finding a new one.

          For this mission type we have two additional properties: "pillage_radius" : {}, which is required and contains "min" and "max" fields to find an attack location in that range around the town's banner; and "target", which is optional and points to a context registration path to use for the attack location (instead of the banner).

        • "wander" -- the mobs will spawn and start wandering in a square pattern. For this encounter type we have two additional fields: "wander_radius" : {}, which is required and contains "min" and "max" properties for a range to randomize the size of the square (so that they don't walk always in the same place); and "walk_interval", which is optional and it's a time expression for how often to walk to the next location ("30m" by default).

City raid

A raid, which is just a group of missions started at the same time at the previous enemy location (set by a create camp encounter or a create mission encounter). Unlike the create mission encounter, this encounter does not do a search for a place to spawn the encounter.

  • "encounter_type" : "city_raid"

  • "city_raid_info" : {}

    • "continue_on_disconnect" -- optional field. For this encounter it doesn't seem to run code since we don't search for a place to spawn the raids.
    • "missions" : {} -- contains entries with custom identifiers, each of which holds the same properties than for the "mission: {}" field from the create mission encounter.