Starbound

Starbound

Not enough ratings
Modding: Monster Spawners Guide
By Ceterai
This guide will tell you how to make objects, projectiles, items, turrets, weapons and status pods that spawn monsters/critters/bugs/etc, like monster eggs in minecraft.
WEBSITE[ceterai.github.io] | SUPPORT ME[buymeacoffee.com]
   
Award
Favorite
Favorited
Unfavorite
Introduction
In this guide, you will learn, how to make:
  • Objects that spawn monsters nearby periodically or when switched or when broken
  • Projectiles that spawn monster(s) on impact
  • Items that can be thrown to spawn a monster
  • Weapons that shoot projectiles that spawn monsters on impact
  • Turrets that shoot projectiles that spawn monsters on impact
  • Status Pods that, when activated, burst with projectiles that spawn monsters
  • Monsters that periodically spawn their minions around them when calm or aggro'ed or both
By monsters I mean regular enemy creatures, critters, bugs and farm animals.
Objects-Spawners
Objects can spawn monsters (and NPCs!) on breaking, on switching wiring input, on interaction and periodically.

All you need to do to configure this is to edit your object's ".object" JSON file.

Take a look at the Alta Security Stand[github.com] from My Enternia as an example of some of these features.
"category" : "spawner", // purely for tooltips "scripts" : [ "/objects/spawner/monsterspawner.lua" ], // important - spawner logic "scriptDelta" : 10, "inputNodes" : [ [-1, 0] ], // in case your spawner needs to be turned on to work "spawner" : { "monsterTypes" : ["smallquadruped", "largequadruped"], // type of monster to spawn (random from list) "monsterLevel" : [1, 10], // level of monster to spawn (random within range, or leave blank for world threat level) "monsterParams" : { // additional parameters of spawned monster "aggressive" : true }, "position" : [0, 1], // relative position to spawn at "positionVariance" : [10, 0], // [x,y] size of randomized spawn area, centered on position "frequency" : [5.0, 5.0], // cooldown time between spawns (random within range) "stock" : 5, // total number of spawns, -1 for infinite "trigger" : null, // options include "wire", "interact", "break", null (periodic) "outOfSight" : false // only spawn where the player can't see },

This method is used in vanilla by Tentacle Eggs, located here:
/objects/biome/tentacle/tentaclespawner1/
Other examples can be found in assets on this path:
/objects/spawner/

NPC Object-Spawner
Apparently, there's also a vanilla script that makes objects spawn NPCs (similar to colony deed), but I have'nt tested it myself.
"category" : "spawner", "scripts" : [ "/objects/spawner/spawners/spawner.lua" ], "scriptDelta" : 1, "spawner" : { "searchRadius" : 32.0, "npcSpeciesOptions" : [ "apex" ], "npcTypeOptions" : [ "villager" ], "npcParameterOptions" : [ { "dropPools" : [ ] } ] }
Examples can be found in assets on this path:
/objects/spawner/spawners/
Projectiles-Spawners
This will be our main trick for the next sections of the guide: a projectile, that spawns a monster (or an NPC!) when it lands.

Projectiles are defined in ".projectile" JSON files, usually located in the "/projectiles/" folder.

To make this work, we are going to rely on a very specific projectile logic file, that is originally used by the vanilla Capture Pod[starbounder.org].

In order to create your projectile, I recommned copying the original "/projectiles/throwable/filledcapturepod/filledcapturepod.projectile" one from the capture pod and editing it:
{ "projectileName" : "filledcapturepod", // your projectile ID. Must be unique. "image" : "filledcapturepod.png", "animationCycle" : 0.25, "physics" : "grenade", "frameNumber" : 1, "pointLight" : false, "speed" : 40, "power" : 0.1, "damageKind" : "default", "emitters" : [ "capturepodred" ], // can remove this if you don't want any effects on trail "bounces" : -1, "piercing" : true, "pureArcDuration" : 1, "returnCollisionDuration" : 2, "orientationLocked" : true, "scripts" : [ "filledcapturepodprojectile.lua" ], // important - logic that spawns the monster "returns" : false, "returnCollisionPoly" : [ [-0.25, -0.25], [0.25, -0.25], [0.25, 0.25], [-0.25, 0.25] ], "collisionPoly" : [ [ -1, -1 ], [ 1, -1 ], [ 1, 1 ], [ -1, 1 ] ], "controlForce" : 80, "pickupDistance" : 1.0, "snapDistance" : 4.0, "podUuid" : null, "monsterType" : "poptop", // ID of the monster we want to spawn "monsterLevel" : 1 }
More about projectile variables you see in that codeblock: Modding: JSON Variables - Projectiles[starbounder.org]
Note: there are 2 projectiles used by the Capture Pod - "capturepod" and "filledcapturepod". We're using the second one because that's the one that spawns monsters.
Note: to spawn an NPC, you'll need to edit the Lua code used here slightly. Checkout the Lua Usage section for helpful info.
Items-Spawners (Monster Eggs)
First, create a monster-spawning projectile as described in the third section of the guide.

Just like the projectile itself, we'll base this off of a capture pod, specificall the NPC version. Starbound has NPC-specific versions for some active items, meant to be held by NPCs instead of the player. This is the one we're going to use, because it sets a monster type explicitly, rather than relying on what's been captured.

It's located here: "/items/active/unsorted/filledcapturepod/npcpetcapturepod.activeitem"

{ "itemName" : "npcpetcapturepod", "maxStack" : 1, "rarity" : "Common", "category" : "throwableItem", "description" : "Throw it down to release the creature captured inside!", "shortdescription" : "Filled Capture Pod", "tooltipKind" : "filledcapturepod", "twoHanded" : false, "itemTags" : ["weapon","ranged"], "inventoryIcon" : "filledcapturepodicon.png", "animation" : "filledcapturepod.animation", "animationParts" : { "filledcapturepod" : "filledcapturepod.png" }, "animationCustom" : { }, "scripts" : ["npcpetcapturepod.lua"], "icons" : { "healthy" : "/items/active/unsorted/filledcapturepod/filledcapturepodicon.png", "dead" : "/items/active/unsorted/filledcapturepod/filledcapturepodicondead.png" }, "stances" : { "idle" : { "armRotation" : -20, "animationState" : { "weapon" : "visible" }, "allowRotate" : true, "allowFlip" : true }, "windup" : { "duration" : 0.1, "transitionFunction" : "fire", "armRotation" : 70, "animationState" : { "weapon" : "visible" }, "allowRotate" : false, "allowFlip" : false }, "throw" : { "armRotation" : 0, "animationState" : { "weapon" : "hidden" }, "allowRotate" : true, "allowFlip" : true } }, "projectileType" : <your projectile ID>, "projectileParameters" : { "speed" : 40, "level" : 0 }, "pets" : [ // list of possible mosters to spawn "gleap", "voltip", "bobfae", "smallbiped", "smallquadruped", "smallflying" ] }
Weapons-Spawners (Monster Egg Shooters)
First, create a monster-spawning projectile as described in the third section of the guide.

This one is pretty simple. Copy any weapon you like that fires projectiles (you can check that by seeing if the weapon's ".activeitem" JSON file contains "projectile..." params).

To set it to fire your projectile, change the "projectileType" param in the "primaryAbility" section (or add one there if there's none) to your projectile ID:
"primaryAbility" : { ... "projectileType" : <your projectile ID>, ... },

Secondary Ability
You can do the same thing for your weapon's secondary (alt) ability, if it has one and it uses projectiles:
"altAbility" : { ... "projectileType" : <your projectile ID>, ... },

Weapons Without Abilities
Some weapons that use projectiles have the projectile type located in the root, rather than within an ability, like boomerangs or chakrams:
"projectileType" : <your projectile ID>,
Turrets-Spawners (Monster Egg Turrets)
First, create a monster-spawning projectile as described in the third section of the guide.

Turrets are objects that will automatically shoot projectiles at targets, for example Defense Turret[starbounder.org], located at "/objects/wired/standingturret/standingturret.object".

Let's use it as a base for our turret:
{ "objectName" : "standingturret", "colonyTags" : ["wired","combat"], "printable" : false, "rarity" : "Common", "objectType" : "container", "price" : 150, "slotCount" : 0, "uiConfig" : "/interface/turret/standingturret.config", "frameCooldown" : 5, "autoCloseCooldown" : 3600, "description" : "Turret for your protection! Can only be placed once.", "shortdescription" : "Defense Turret", "subtitle" : "Automatic Base Defense", "race" : "generic", "category" : "wire", "breakDropOptions" : [ [ [ "siliconboard", 1, { } ], [ "wire", 1, { } ] ] ], "inventoryIcon" : "icon.png", "orientations" : [ ... ], "scripts" : [ "/objects/wired/standingturret/standingturret.lua", "/scripts/npcToyObject.lua", "/scripts/stateMachine.lua", "/scripts/util.lua", "/scripts/vec2.lua" ], ... }

What makes this section difficult is that you will also need to edit the attached Lua logic slightly so that you can set the projectile type to fire:
  1. Copy the "/objects/wired/standingturret/standingturret.lua" and open it.
  2. Find a line that has "world.spawnProjectile("standardbullet"" in it.
  3. Change "standardbullet" to config.getParameter("projectileType"), like so:
    world.spawnProjectile(config.getParameter("projectileType"), ...
  4. Add ""projectileType" : <your projectile ID>" to your projectile's ".projectile" file.
  5. Change the according script path in ""scripts"" to your new Lua file.

Apex Turret
There's also a simpler version, located in "/objects/apex/turret/turret.object":
{ "objectName" : "apexturret", "colonyTags" : ["apex","apexresearchlab","combat","electronic"], "rarity" : "Common", "category" : "wire", "price" : 400, "description" : "The finest automated security turret around.", "shortdescription" : "Hi-tech Turret", "race" : "apex", "printable" : false, "inventoryIcon" : "icon.png", "orientations" : [ ... ], "scripts" : [ "/objects/apex/turret/turret.lua", "/scripts/stateMachine.lua", "/scripts/util.lua", "/scripts/vec2.lua" ], "animation" : "turret.animation", "animationParts" : { "gun" : "turret.png", "bracket" : "turret.png", "beam" : "beam.png" }, "scriptDelta" : 5, "outputNodes" : [ [0, 0] ], "rotationTime" : 2.5, "rotationRange" : [0, 60], "rotationPauseTime" : 0.5, "maxLaserLength" : 20, "baseOffset" : [1.625, 0.9375], "tipOffset" : [3.375, 0.875], "fireCooldown" : 0.05, "fireOffsets" : [-0.25, -0.125, 0, 0.125, 0.25, 0.125, 0, -0.125], "targetHoldTime" : 2 }

Once again, you will also need to edit the attached Lua logic slightly so that you can set the projectile type to fire:
  1. Copy the "/objects/apex/turret/turret.lua" and open it.
  2. Find a line that has "world.spawnProjectile("bullet-1"" in it.
  3. Change "bullet-1" to config.getParameter("projectileType"), like so:
    world.spawnProjectile(config.getParameter("projectileType"), ...
  4. Add ""projectileType" : <your projectile ID>" to your projectile's ".projectile" file.
  5. Change the according script path in ""scripts"" to your new Lua file.
Status Pods-Spawners (Monster Egg Dispencers)
First, create a monster-spawning projectile as described in the third section of the guide.

The original Status Pod[starbounder.org] is located here: "/objects/generic/statuspod/statuspod.object"

You can either create your own, or patch the original one to include your projectile in its pool.

But first, you might want to create an additional spray projectile, that will spray your projectile everywhere. You don't have to do this, and can use your original prjectile, but it will only create one monster that way.

Spray Projectile
A regular projectile that spawns other projectiles on contact/death, usually these are located in here: "/projectiles/status/"

For example:
{ "projectileName" : "bombstatusprojectile", "physics" : "statuspod", "bounces" : -1, "timeToLive" : 1.5, "speed" : 0, "damageKindImage" : "icon.png", "image" : "bombstatusprojectile.png", "animationCycle" : 0.5, "frameNumber" : 4, "periodicActions" : [ { "time" : 0.35, "loop" : true, "action" : "projectile", "type" : <your monster spawning projectile ID>, // the "projectileName" of your first proj. "fuzzAngle" : -250 } ], "power" : 0, "piercing" : true, "damageKind" : "hidden", "damageType" : "ignoresdef", "damagePoly" : [ [-80, -80], [-80, 80], [80, 80], [80, -80] ], "flippable" : true, "damageTeam" : { "type" : "indiscriminate" } }

Create Your Own Status Pod
If you'd rather create your own status pod-like object than editing the existing one, here is an example of what you would need:
{ "objectName" : "statuspod", "colonyTags" : ["misc"], "rarity" : "Common", "printable" : false, "category" : "other", "price" : 500, "description" : "A status pod. Take your chances...", "shortdescription" : "Status Pod", "race" : "generic", "scripts" : [ "/scripts/statusProjectileObject.lua" ], "scriptDelta" : 10, "activationTime" : 900, "animation" : "/objects/generic/statuspod/statuspod.animation", "animationParts" : { "pod" : "statuspod.png" }, "animationPosition" : [-8, 0], "projectileOptions" : [ // this is where you'd add your projectile { // some examples for you "projectileType" : <your projectile ID>, // either your first proj or your spray proj "projectileParams" : { } }, ... { "levelRange" : [3, 10], // you can set environment level range as a condition for an option "projectileType" : "silverbombstatusprojectile", // projectile example "projectileParams" : { } // optional parameter overrides }, { "levelRange" : [5, 10], "projectileType" : "goldbombstatusprojectile", "projectileParams" : { } } ] }

Patching Vanilla Status Pod
Editing vanilla JSON files safely should be done via patching. Read more about it here:
https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=2124444255
You'll need to create a patch file in your mod at this path:
<your mod>/objects/generic/statuspod/statuspod.object.patch
Now, add this patch to it:
[ { "op" : "add", "path" : "/projectileOptions/-", "value" : { "levelRange" : [3, 10], // optional, set environment level range as a condition for an option "projectileType" : <your projectile ID>, // either your first proj or your spray proj "projectileParams" : { } // optional parameter overrides } ]
That's it!
Minion Spawners
This one is pretty simple.

1. Monsters can passively spawn certain other monsters around them periodically, until they reach a max amount of minions at the same time.

2. They can also spawn monsters on death, or on hit, or as an attack, allowing you to make a second stage for your monster or just spawn a lot of minions, or anything you feel like!

3. Lastly, you can make monsters attack you by launching projectiles that spawn monsters at you or in specific directions.
 
All of this can be easily configured through a monster action.

If you open any ".monstertype" JSON file (monster definition file) you will likely find a lot of lists called "fleeActions", "attackActions", etc. These are sets of monster actions, that are executed in specific cases, like fleeing, attacking, etc.

Take a look at the Frigate Drone[github.com] from My Enternia as an example of some of these features.

Passive Spawn
Create a monster action of type "action-spawncompanions":
{ "name" : "action-spawncompanions", "parameters" : { "maxCount" : 3, // max amount of concurrent minionsm default is 1. "spawnCooldown" : 5.5, // time between spawns, can be a range ([a, b]), default is 5. "position": {"key" : "self"}, // absolute spawn position, default is null. "offset": [0, 0.5], // relative x/y spawn position offset, default is [0, 0]. "monsterType" : <your monster ID> // the type name of your monster, default is "". } }
Now, put it either in "concurrentActions" list, or in "concurrentHostileActions", or in both:
"concurrentActions" : [ { "name" : "action-spawncompanions", "parameters" : { "maxCount" : 2, "spawnCooldown" : 3, "monsterType" : "poptop" } } ], "concurrentHostileActions" : [ { "name" : "action-spawncompanions", "parameters" : { "maxCount" : 3, "spawnCooldown" : 5, "monsterType" : "ciclesnailcritter" } }, { "name" : "action-spawncompanions", "parameters" : { "maxCount" : 1, "spawnCooldown" : 1, "monsterType" : "poptop" } } ],
As you can see, configurations can be different from each other.
Concurrent actions are actions made by the monster passively in non-aggro state. Hostile concurrent actions are passive monster actions in aggro state.
This method is used in vanilla by Tentacle Spawners[starbounder.org] and Mother Poptop[starbounder.org].

On Death/Attack/Take Hit Spawn
Create a monster action of type "action-spawncompanions":
{ "name" : "action-spawnmonster", "parameters" : { "position" : "self", // absolute position, default is "self". "offset" : [0, 0.5], // relative x/y offset, default is [0, 0]. "monsterType" : <your monster ID>, // your monster, default is "smallbiped". "replacement" : true, // whether it will replace the current monster, default is false. "parameters" : { "health" : 20 } // parameters passed to the monster, default is { }. "damageTeam": null, // default is null. "damageTeamType": null, // default is null. "inheritParameters": [ ], // list of parameters to inherit from current monster, default is { }. "level": 3 // default is null. } }
Now, put it in "deathActions" list if you want it to happen when the monster is defeated:
"deathActions" : [ { "name" : "action-spawnmonster", "parameters" : { "offset" : [0, 0.5], "monsterType" : "bobfae", "replacement" : true, "parameters" : { "health" : 20 } } }, { "name" : "action-spawnmonster", "parameters" : { "offset" : [0, -0.5], "monsterType" : "poptop", "replacement" : true } } ]
Otherwise, try putting it in "hostileActions" or "damageTakenActions" to trigger on attack or getting hit respectively.
This method is used in vanilla by Nutmidges[starbounder.org] and Hemogoblins[starbounder.org].

Projectile Attacks
Add an "action-fire" to your "hostileActions", using a projectile you made in the third section of this guide:
"hostileActions" : [ { "name" : "action-fire", "cooldown" : 2.0, "parameters" : { "requireLineOfSight" : true, "maximumRange" : 20, "minimumRange" : 3, "windupStopForce" : 50, "windupState" : "fire", "windupTime" : 0.3, "projectileType" : <your projectile ID>, "projectileParameters" : { "speed" : 25 }, "fireOffset" : [0.5, -1.5], "aimAtTarget" : true, "onGround" : false, "fireState" : "", "fireSound" : "fire", "winddownState" : "idle", "winddownTime" : 1.5 } } ],
Lua Usage
You can create your custom Lua scripts to use for your items, objects, monsters and projectiles.

There are predefined Lua functions in Starbound that let you spawn either a monster or an NPC.

Monsters
To spawn a monster via Lua, use the following "world.spawnMonster()" method:
EntityId world.spawnMonster(String monsterType, Vec2F position, [Json parameters]) Attempts to spawn a monster of the specified type at the specified position. If parameters are specified they will be applied to the spawned monster. If they are unspecified, they default to an object setting aggressive to be randomly true or false. Level for the monster may be specified in parameters. Returns the EntityId of the spawned monster if it is run from a server-side entity and is successful, or nil.
Source: Modding: Lua Tables - World[starbounder.org]

NPCs
To spawn a monster via Lua, use the following "world.spawnNpc()" method:
EntityId world.spawnNpc(Vec2F position, String species, String npcType, float level, [unsigned seed], [Json parameters]) Attempts to spawn an NPC of the specified type, species, level with the specified seed and parameters at the specified position. Returns EntityId of the spawned NPC if successful and nil otherwise.
Source: Modding: Lua Tables - World[starbounder.org]

Projectiles
To spawn a projectile via Lua, use the following "world.spawnProjectile()" method:
EntityId world.spawnProjectile(String projectileName, Vec2F position, [EntityId sourceEntityId], [Vec2F direction], [bool trackSourceEntity], [Json parameters]) Attempts to spawn a projectile of the specified type at the specified position with the specified source entity id, direction, and parameters. If trackSourceEntity is true then the projectile's position will be locked relative to its source entity's position. Returns the EntityId of the spawned projectile if successful and nil otherwise.
Source: Modding: Lua Tables - World[starbounder.org]
Conclusion
This is all I have to share on this topic. Let me know if there's anything I'm missing! ^^
Helpful Resources
More about monster spawners:
https://starbounder.org/Monster_Spawner

More about NPC spawners:
https://starbounder.org/Spawner

An fairly old video that also takes you through making an object-spawner:
https://www.youtube.com/watch?v=6BRUXBZ08Wc
7 Comments
Ceterai  [author] 19 Jan @ 12:47pm 
Now, why does it work for the Kluex boss, who does use inheritParameters ?

The problem is that the Kluex Statue has custom behavior called kluexbossstatue ( /behaviors/monsters/boss/kluexbossstatue/kluexbossstatue.behavior ) which uses the spawnMonster node in it, instead on relying on modular behavior.

If you open the statue's .monstertype file ( /monsters/boss/kluexbossstatue/kluexbossstatue.monstertype ), you won't see the usual ...Actions \-type lists of actions - you'll still see a behavior and behaviorConfig , but they'll be different to what most monsters have in them.

Obviously, you could use statue's behavior, but then I think your monster would be tied to that behavior specifically. Not sure if there's a way to combine the two easily though. (3/3)
Ceterai  [author] 19 Jan @ 12:46pm 
Finally, add your action to the /behaviors/nodes/module.nodes file using patching.

There, it will look similar to this:

"action-spawnmonster-new": { // your action name
"type": "module",
"name": "action-spawnmonster-new",
"title": "",
"properties": {
"position": {"type": "position", "key": "self"},
"offset": {"type": "vec2", "value": [0, 0]},
"monsterType": {"type": "string", "value": "smallbiped"},
"replacement": {"type": "bool", "value": false},
"inheritParameters": {"type": "table", "value": []} // in case you want a default & want it to be empty
}
},
(2/3)
Ceterai  [author] 19 Jan @ 12:44pm 
Someone on reddit asked an interesting question about using inheritParameters in monster actions, in the Minion Spawners section, as it didn't work for them when they passed it to the action-spawnmonster action. Posting here as well:

It's meant to be used by the spawnMonster behavior node used by the action-spawnmonster action.

If it doesn't work for you, you could try to create your own action similar to the original one (located in /behaviors/monsters/modular/movement/spawnmonster.behavior ) and pass the inheritParameters param explicitly to the spawnMonster node, similar to how "position", "replacement" and "type" are passed. (1/3)
Ceterai  [author] 9 Dec, 2024 @ 1:40pm 
Glad I could help ^^
To be clear - since dungeons are saved in JSON format, it's possible to edit monsters in them without Tiled - by directly changing their properties in the file, but I wouldn't recommend that as it's much safer to do with Tiled.
🦊 Hermit 9 Dec, 2024 @ 7:55am 
Ah, so that's a little more complex than just editing config files then? That explains why I could never find any results when trying to Google it lol. Thanks very much for the info though, now you've given me a start point I can perhaps go into it in more detail and maybe figure out the details :104::PhogsHappy: Appreciate the pointers^^
Ceterai  [author] 9 Dec, 2024 @ 5:20am 
That's actually a good idea - though could be just a paragraph in this guide I think

As far as I know, this boils down to editing the dungeon in Tiled by placing monster rectangles in your dungeon on the "monsters" layer, and adding necessary properties to it. Similarly, if you want to edit an existing one, you just find it within the dungeon and edit its properties.
There's a dedicated section on Starbounder Tiled guide that takes you through the process: Modding: Tiled/Example Mission - Monsters [starbounder.org]
And a general guide on what Tiled is & how to use it: Modding: Tiled [starbounder.org]
🦊 Hermit 8 Dec, 2024 @ 8:16pm 
Your guides are very comprehensive and well written, thanks for your work^^

Out of curiosity, do you have any plans to write a guide on how to edit monster spawns within the game's dungeons? I'd be very interested in that one if you made it, but no pressure if not.