[Tutorial] Adding custom creatures

Hey guys! Thought it was high time to put one of these up, so here you go; enjoy!

2.3 - Mastering ambient threats


Here you’ll learn how to add creatures as ambient threats. We’re gonna use the game master to do this, but we’re only going to scratch the surface on the game master as there’s a lot of it to cover just for this section. You should also take a look at Stephanie’s video on how to mod with the game master; check it out over here.

What we want to do with the game master (and because we’re using our own kind of creatures) we also have to implement our own population, so we’ll be touching on that subject a bit also.


2.3.1 - Populations


Populations are fairly straightforward to implement, though the population you’re about to see is only a small part of what it could contain, but it’s enough for what we want. So let’s see what’s in a minimal population definition:

{
   "kingdom_name" : "Spiders",
   "kingdom_id" : "spiders",
   "amenity_to_strangers" : "hostile",

   "roles":
   {
      "minion":
      {
         "male":
         {
            "uri" : [ "ambient_gm_mod:spiders:minion" ]
         }
      }
   }
}

As before, let’s go over it in detail.

  • "kingdom_name" - The name of the population (obviously), it’s used to get an easy to read text for the player.
  • "kingdom_id" - Another name of the population, but this is used internally and should be kept as a single word only.
  • "amenity_to_strangers" - How the creatures from this population acts when approaching creatures from other populations. It’s completely optional, and is by default set to “neutral” (a third option to use is “friendly”).
  • "roles" - This is where all the creatures are defined.
    • "minion" - The name of our role.
      • "male" - Gender! Obviously there’s also a female variant, but if you only have one gender for your role you should always choose male even if they would be considered female. This is because, when creating a new creature, the game chooses one of the genders randomly, and if the gender it chose isn’t available it will choose male by default.
        • "uri" - An array pointing to the creatures’ definition files that are connected to this particular role.

As said before; this is only a small part of what a population definition can contain. You can have it contain names for each role, names for its town, among other things.
If you want to see how to implement such things then I’d recommend that you take a look at an existing population definition file within the stonehearth mod, they’re located in stonehearth/services/server/population/data.

After this we’ll need to make sure that the population gets registered correctly, in a way that’ll make it an NPC population. We’ll create a new json file with the name “npc_index.json” which will be mixinto’d from the manifest.

{
   "spiders":
   {
      "kingdom" : "ambient_gm_mod:kingdoms:spiders"
   }
}

That’s all npc_index.json will contain, not really too hard to see what’s happening here; we’re defining a new population "spiders" (note: this is also the player_id which will be tied to this population) in which we have another key-value pair. The key is always "kingdom" so don’t change that, and the value is the alias to our population definition. Simple as that!

We also have to add all this to the manifest, but let’s take a look at it after we’ve added an ambient threat.


2.3.2 - Ambient threats


Right, we’ve set up a population so now we’re ready to create our encounters! We’re going to keep this simple and only have a couple of our own encounters for this, we’re also going to need a couple of files to mixinto to the existing ambient threats list. Let’s look at the encounters we’re creating first (with the first one being “spider_pack.json”).

{
   "type" : "encounter",
   "encounter_type" : "wait_for_time_of_day",
   "rarity" : "common",
   "in_edge" : "spider_pack",
   "out_edge" : "spider_raid",
   "wait_for_time_of_day_info":
   {
      "time" : "21:00+2h30m"
   }
}

Right, let’s go over this now.

  • "type" - As before, this describes what type this file defines, have this be "encounter" for everything relating to your campaign.
  • "encounter_type" - What kind of encounter this is. There are a handful to choose; we’ll be covering a couple only, but if you want to see what other types there are; you can find them in stonehearth/services/server/game_master/controllers/encounters.
  • "rarity" - Can be either "common" or "rare." As you can imagine, this says what’s the chance for this particular encounter will occur. It’s used when choosing between several encounters that share that same value from "in_edge."
  • "in_edge" / "out_edge" - These two decide where to go after an encounter is finished. When an encounter has finished its purpose it will look for other encounter’s "in_edge" value that shares the current encounter’s "out_edge" value. The first encounter in any campaign has its "in_edge" value as "start" though we’re not starting a campaign here so we don’t have to worry about that sort of stuff.
  • "wait_for_time_of_day_info" - All data that’s relevant to this encounter, it always has the name of the encounter type with the postfix “_info.” Other encounter types have different kind of data associated with them.
    • "time" - What in-game time this encounter will occur in. The interesting thing here is the “+”; what this means is that we’re setting a sort of interval of when this encounter will happen; so as to have some random variable, and not have it occur at the exact same time of day every time. In this example the encounter will happen sometime between the times 21:00 and 23:00.

That’s the first of our encounters, let’s go straight to the next file in line (“spider_raid.json”).

{
   "type" : "encounter",
   "encounter_type" : "create_mission",
   "rarity" : "common",
   "in_edge" : "spider_raid",
   "create_mission_info":
   {
      "spawn_range":
      {
         "min" : 80,
         "max" : 190
      },
      "mission":
      {
         "npc_player_id" : "spiders",
         "ctx_entity_registration_path" : "spider_raid.raiders",
         "role" : "pillage",
         "offset" : { "x" : 0, "y" : 0, "z" : 0 },
         "pillage_radius":
         {
            "min" : 0,
            "max" : 50
         },
         "sighted_bulletin":
         {
            "title" : "Eek! Creepy crawlies!"
         },
         "members":
         {
            "spiders":
            {
               "from_population":
               {
                  "role" : "minion",
                  "location" : { "x": 0, "z": 0 },
                  "min" : 2,
                  "max" : 3,
                  "range" : 30,
                  "scale_with_run":
                  {
                     "encounter_cap" : 1
                  }
               }
            }
         }
      }
   }
}

This is somewhat bigger, but let’s go over what’s new in here:

  • "create_mission_info" - As mentioned just before, this has the same name as the encounter type with “_info” stuck at the end. This kind of encounter starts a sort of mission for our creatures; a mission to destroy you! (well, that escalated quickly)
    • "spawn_range" - How far away to spawn from the player’s town.
    • "mission" - The information concerning this mission.
      • "npc_player_id" - The player id to use to find a population.
      • "ctx_entity_registration_path" - This isn’t really relevant for this section, but it’s good that you know about it. It’s pretty much a path to find the entities created from this encounter. Say, for example, that you’d want to destroy the entities from here, then you’d use this path to find them and then end them.
      • "role" - What role this kind of mission has. The other value you can use is "raid_stockpiles."
      • "offset" - An offset of where the creatures will spawn.
      • "pillage_radius" - The raiders will choose a point within this area relative to the player’s banner.
      • "sighted_bulletin" - The message that will pop up when a citizen spots the raiders.
      • "members" - Information of the creatures that will spawn.
        • "spiders" - A name for this particular member group.
          • "from_population" - It could be either this or "from_ctx", the difference is that with this one we’re using it will create and spawn new creatures, whilst "from_ctx" will use creatures which have been created previously.
            • "role" - The particular role of these creatures, this value comes from the population definition’s role value.
            • "location" - An offset for this member, each member type can have their own location values if you’d want them to not spawn to close to each other (as an example of usage).
            • "min" / "max" - How many creatures to spawn, it will be a random value between these two.
            • "range" - How big of an area these creatures spawn in.
            • "scale_with_run" - If the amount of creatures spawned will increase every time this particular encounter runs.
              • "encounter_cap" - A limit for how much this encounter can be scaled.

Note that we’re don’t have an "out_edge" value here, that’s because we don’t want anything more to happen after this encounter.

Right, now that we’ve looked at the encounters we want to make, let’s take a look at another encounter (“randomize_daily_threat.json”); though this is of one that already exists in the stoneahearth mod and will be used as a mixinto.

{
   "random_out_edge_info":
   {
      "out_edges":
      {
         "spider_pack" : { "weight" : 3 }
      }
   }
}

Not much to cover here, but let’s go over it as per usual.

  • "random_out_edge_info" - This is the info of an encounter type "random_out_edge", as mentioned just recently, this will be used as a mixinto so we don’t have to define an "encounter_type" or any of the other common values for that matter.
    • "out_edges" - All the different out edges that can occur, only one of the edges listed under here will be chosen.
      • "spider_pack" - The "out_edge"'s name (which has the same name as the "in_edge" of the first encounter we looked at).
        • "weight" - The chance of this particular out_edge to be chosen; the higher the value the greater the chance (the undead raid threat has a weight of 6).

And now we look at the final file (“ambient_threats_arc.json”) which will also be used as a mixinto.

{
   "encounters":
   {
      "spider pack" : "file(encounters/spider_pack.json)",
      "spider raid" : "file(encounters/spider_raid.json)"
   }
}

This file is really important as it tells the game what encounters there are to use; since we’re creating two new encounters we’ll only be listing those here, but if you were to create more encounters you have to add them in here as well.


We’re almost done, now we just need to define out manifest and we’re good to go! Before looking at the manifest though; here’s how the folder structure looks like for this mod example, to give you a reference for how the manifest will look like.

Yes, there are a lot of folders within the gm, but there’s a reason for that (trust me).

Right, now we can take a look at how the manifest looks like after all we went through.

{
   "info":
   {
      "name"    : "Ambient Threats example mod",
      "version" : 1
   },

   "aliases":
   {
      "kingdoms:spiders" : "file(data/populations/spider_population.json)",
      "spiders:minion" : "file(entities/spiders/minion)",
      "spiders:minion:teeth" : "file(entities/spiders/minion/spider_teeth.json)",
      "skeletons:spiders:minion" : "file(data/rigs/spiders/minion)"
   },

   "mixintos":
   {
      "stonehearth/data/npc_index.json" : "file(data/populations/npc_index.json)",

      "stonehearth/data/gm/campaigns/ambient_threats/arcs/trigger/ambient_threats/ambient_threats_arc.json" :
             "file(data/gm/campaigns/ambient_threats/arcs/trigger/ambient_threats/ambient_threats_arc.json)",
          "stonehearth/data/gm/campaigns/ambient_threats/arcs/trigger/ambient_threats/encounters/randomize_daily_threat.json" :
             "file(data/gm/campaigns/ambient_threats/arcs/trigger/ambient_threats/encounters/randomize_daily_threat.json)"
   }
}

The notable parts here are the first value in "aliases" and the values in "mixintos" though you guys should know by now what happens here. :wink:

Let’s end this off with a screenshot of this example mod in action.


You can do it ms. footman!



And that’s it for this section, hope it helped you modders in adding new and frightening threats!

3 Likes