Other effects

There are some types of effects we haven't talked about yet.

Sound effects

Sound effects in Stonehearth are in .ogg format (to save in filesize).

We can play sounds in Lua (by running the effect they're in) or through Javascript (for example, when we buy something in a shop via the UI). For how to play music and ambient sounds, check this page.

Effects can also have a sound track besides light, animations, or particles. An example sound track for the effect JSON file looks like this:

  "sound": {
     "type": "sound_effect",
     "start_time": 150,
     "min_distance": 27,
     "falloff" : 5,
     "volume": 60,
     "track" : "stonehearth:sounds:death_poof"
  }

These are the fields for the effect file:

  • "type" : "sound_effect" - this effect track is a sound effect.

  • "loop" -- a boolean to loop the sound (false by default).

  • "start_time" -- optional field (defaults to 0). The start time (in milliseconds) at which the sound track should start (in regards to the whole effect). Some sounds are played near the end of the effect, so this might be higher than 0.

  • "end_time" -- optional field (defaults to the natural duration of the sound). The time (in milliseconds) at which the sound track should end.

  • "duration" -- optional field. Duration of the sound track in milliseconds. It doesn't need to match the natural duration of the sound.

    icon The way these four fields interact is:

    • The sound starts at "start_time".
    • If "loop" is set, the sound loops for the "duration".
    • If "end_time" is set, the sound stops being played at "end_time", even if "loop" is true. In this case, "loop" just loops the interval between "start_time" and "end_time" (in regards of the whole duration of the effect, not continuously).
    • If "end_time" is not set, it marks the track as finished when the natural duration of the sound is done.
  • "min_distance" -- optional field (20 by default). The minimum distance (in number of blocks) at which the sound will start to be audible. If we move our camera farther than this distance from the entity that is playing the effect, we'll stop hearing the sound.

  • "max_distance" -- optional field (60 by default). The maximum distance at which the sound will be audible.

    iconNote: for this type of sound that is based on distance / location, make sure that your sound file is exported as mono, not as stereo, otherwise there'll be weird echoing. We can use a high value if we want the sound to be audible from far away.

  • "falloff" -- optional field (defaults to 1). The attenuation for the sound (when at a distance, the sound will be less audible). Can contain decimals.

  • "volume" -- optional field (defaults to 0.1). The volume (from 0.1 to 100) for the sound, in case we need to adjust it because our file is too loud or quiet compared to the rest of the in-game sounds. Will be scaled with the Effects volume from the game's Sound settings.

  • "pitch" -- optional field. The pitch to apply to the sound track.

  • "max_instances" -- optional field. This is useful when many instances of this sound can be running at the same time. For example, if we wanted that only one lullaby is heard regardless of how many hearthlings are sleeping nearby, we'd set this to 1.

    iconMind that for this particular example, when the first hearthling (who started to play the lullaby) wakes up, the sound will stop, no matter if there are other hearthlings nearby still sleeping (they cancelled playing their sounds because we already got to the "max_instances"). If another hearthling goes to sleep after the first one woke up, then the sound will be played again.

  • "repeat" -- optional field (defaults to false). Provided your effect contains at least an animation track and a sound track, we restart the sound when the animation loops. This is normally true without needing this field, but in rare cases where the sound effect has a longer duration than the animation you might want to use it to change how it's played. It depends on the duration / loop / start_time and end_time that you set up for your tracks.

  • "fade_out_time" -- optional field (defaults to 0 / no fade out). Number of milliseconds after which the sound will stop being audible (it will fade out at the end). Don't use if your sound loops.

  • "track" -- required field. The URI of the sound file that we want to play, or this:

    "track" : {
       "type": "one_of",
       "items": [
          "stonehearth:sounds:jobs_trapper_arm_01",
          "stonehearth:sounds:jobs_trapper_arm_02",
          "stonehearth:sounds:jobs_trapper_arm_03"
       ]
    }
    

    In which case, a random sound from the array will be played.

Playing sounds in the UI

This is the syntax for playing sounds in Javascript files:

  radiant.call('radiant:play_sound', {'track' : 'stonehearth:sounds:ui:start_menu:shop_buy'} )

We call the 'radiant:play_sound' function and pass an object that contains the URI of the track that we want to play.

Unit status effects

The bubbles that appear on top of hearthlings when they talk, or the heart that appears when a hearthling loses health are unit status effects.

unit_status_effects

They are achieved by attaching an image that always faces the camera to a bone from the hearthling's rig (or to a certain distance from the center of any entity).

This is an effect track for a unit status effect:

  "unit_status_effect": {
     "type": "unit_status_effect",
     "material": {
        "name": "materials/billboard.material.json",
        "samplers": [
           {
              "name": "albedoMap",
              "map": "materials/thoughts/health/dead/dead_.png",
              "numAnimationFrames": 25,
              "frameRate": 20
           }
        ]
     },
     "width": 2,
     "height": 3.4,
     "xOffset": 0,
     "yOffset": 1.6,
     "duration": 990,
     "bone": "head"
  }

We can see the following properties:

  • "type" : "unit_status_effect" -- this track is a unit status effect.

  • "duration" -- the duration in milliseconds that we want this effect track to last. If you don't specify a duration, it may loop forever depending on the effect, so be careful.

  • "material" : {} -- required field. A render material to render the image. Normally it will point to the billboard material (which renders the image that always faces the camera), and pass the image to show in the "samplers" field (see example above).

    If you want your image to animate, you can set it up like in the example, adding a "numAnimationFrames" and a "frameRate" fields besides the image in "map" ("name" must be "albedoMap"). Notice how the image name ends with an underscore: we have 25 images in that folder (one per frame) called from dead_00.png to dead_24.png. You can use that convention in order to create animated images.

    Another way to animate if you can't use that convention is like this:

    "samplers" : [
       {
          "name" : "albedoMap",
          "map" : "",
          "animation_frames": [
             "materials/thoughts/health/hearts/heart_4_8.png",
             "materials/thoughts/health/hearts/heart_4_8.png",
             "materials/thoughts/health/hearts/heart_5_8.png",
             "materials/thoughts/health/hearts/heart_4_8.png",
             "materials/thoughts/health/hearts/heart_5_8.png",
             "materials/thoughts/health/hearts/heart_4_8.png",
             "materials/thoughts/health/hearts/heart_5_8.png"
          ],
          "numAnimationFrames" : 7,
          "frameRate" : 8,
          "numLoops" : 1
       }
    ]
    

    Specify the paths to the images for each frame in an "animation_frames" : [] field, with a "numLoops" field for how many times it should run. Remember that the paths here will be read from stonehearth/data/horde unless you use an absolute path.

  • "bone" -- optional field, defaults to "head". Unit status effects are meant for animated entities, so it's likely they already have a "head" bone. You can define a different bone to attach the image to here. For some posed entities this points to the "center" bone (make sure the bone exists in your entity's rig).

  • "width" -- optional field, defaults to 3.0. Scale for the width (e.g. 2 is double the width of the image).

  • "height" -- optional field, defaults to 3.0. Scale for the height (e.g. 2 is double the height of the image). Bear in mind that the image will look smaller when you zoom out. If your image is not perfectly square, "height" might need to be slightly bigger than "width" or viceversa in order to keep the proportions.

  • "xOffset" -- optional field, defaults to 0 (we'll subtract half the width from it so that the origin is at the center of the image). Offset in the horizontal coordinate to move the image to (can be negative).

  • "yOffset" -- optional field, defaults to 0 (will get scaled if the entity is scaled, to adjust to its height). Offset in the vertical coordinate to move the image to (can be negative). Similarly to the width and height, the offsets are defined in units, not in pixels.

The following fields are only used in stonehearth/data/effects/thoughts/thought_bubble_base.json, but you can use them too for your effect if you want:

  • "xScalePivot" -- optional field, defaults to 0.5. The pivot for scaling the image horizontally.
  • "yScalePivot" -- optional field, defaults to 0.5. The pivot for scaling the image vertically. These are positions relative to the image, so the defaults mentioned point to the center of the image.
  • "detach" -- optional field, defaults to false. When true, the image will be detached from the bone when it's created, and will get attached after that. By default the images are created directly attached to the bone.
  • "entryAnimation" : {} -- optional field. Parameters for animating the image when it appears.
  • "exitAnimation" : {} -- optional field. Parameters for animating the image when it disappears. Take a look at thought_bubble_base.json to check which fields to use for entry/exit animation.

You can find more examples of unit status effects in stonehearth/data/effects, although the effects there are mixed. There's also some unit status effects that have an animation track, those are under the stonehearth/data/rigs folder, but finding them is harder.

Activity overlay effects

The toast that appears hovering above an entity when we mark it for harvesting, looting, etc. is an activity overlay effect.

activity_overlay_effects

This is mostly used for non-animated entities. Example of an activity overlay track:

  "activity_overlay_effect": {
     "type" : "activity_overlay_effect",
     "material" : {
        "name": "materials/overlay.material.json",
        "samplers" : [
           {
              "name" : "foregroundMap",
              "map": "materials/harvest_plant_overlay/harvest.png"
           },
           {
              "name" : "albedoMap",
              "map": "materials/thoughts/default_overlay.png"
           }
        ]
     },
     "y_offset" : -10
 }

These are the fields that we can find in an activity overlay effect track:

  • "type" : "activity_overlay_effect" -- this is an activity overlay effect track.

  • "material" : {} -- a render material to render the image. Normally it will point to the overlay material, and pass the images to show in the "samplers" field (see example above).

    Normally we'll have an entry for the "foregroundMap" for the main image (make it with a transparent background), and one entry for the "albedoMap" variable for the background image (normally points to default_overlay.png, which is the square bubble image, will be tinted with the player color in multiplayer).

    Remember that the paths to the images will be read from stonehearth/data/horde by default unless we use an absolute path.

  • "width" -- optional field (defaults to 64). The width for the image.

  • "height" -- optional field (defaults to 64). The height for the image. Unlike with unit status effects, "width" and "height" for overlay effects are defined in pixels.

  • "y_offset" -- optional field. The offset to place the image vertically above the center of the entity. Unlike with unit status effects, "y_offset" for overlay effects is defined in pixels. Defaults to 0, but will still appear above the entity so you can use negative values if you want to lower it - be careful since high negative values can make it sink into the terrain on certain camera positions/rotations.

Trigger effects

In a previous section we talked about some syntax for the attach item track that can only be seen for the promote effect, and it's dependent on the AI action. The promote effect also has several "trigger_effect" tracks, which aren't used anywhere else in the code (likely because we can trigger and listen to events more easily from Lua). This effect has animation, sound and cubemitter tracks, besides several trigger effect tracks.

You'll rarely want to use this, since there might be easier/other ways to do this, but here's the example:

  "promote_trigger" : {
     "type": "trigger_effect",
     "start_frame": 145,
     "info": {
        "event": "change_outfit",
        "talisman": "{{talisman}}"
     }
  }

The properties are:

  • "type" : "trigger_effect" -- this track is a trigger effect.
  • "start_frame" -- the frame at which the track should trigger.
  • "info" : {} -- the info about the event to trigger. It has an "event" field with an event key, and a "talisman" field (which is custom data, also retrieved from the arguments passed to the 'stonehearth:run_effect' action). In change_job_using_talisman_action.lua we create a trigger function (think of it as a callback) to pass to the promote effect when we run it. It then runs code depending on the "event" to promote the hearthling, removing the talisman and assigning their tool via the job component.

Creating other effects with SHED

We already mentioned one way to create effects with SHED. There's another option: go to the Effects Editor, find a similar effect than what you want to create in the 'Effects' tab. Right click on it, click on 'Clone', change the target mod to your mod and provide a replacement name.

cloning_effect_from_effects_tab

Then confirm, and the tree view will refresh to add your effect. Edit it since the replacement texts might be pointing to unexisting files and change the rest of properties to what you want to.

With this method you will need to add an alias for the effect separately, but you can do so in the Manifest view: right click in your mod's name, click on 'Add New Alias', select the file that was created, and then a popup will appear for you to edit the alias.

With the other method the alias will be generated when cloning the effect file, so it might be faster. You'll need to create any additional files separately, or reuse some from the stonehearth mod.