Welcome to the Stickforge NPC Modding Guide! This document will walk you through the process of creating your own Non-Player Characters (NPCs), from simple stationary objects to complex, AI-driven humanoids.
I recommend you keep the sf_base
mod's npcs
folder open as a reference. You can find it at stickforge-server/mods/sf_base/npcs
. By examining the existing NPCs, you can get a clear understanding of how different properties are used.
IMPORTANT: NPC SYSTEM IS CURRENTLY EXPERIMENTAL. IT WORKS WELL WITH MAPS WITH HORIZONTAL GAMEPLAY BUT AS LONG AS THERE IS VERTICAL GAMEPLAY (PLATFORMS IN MID-AIR) IT WON'T WORK WELL.
Example: Forest Edge (Conquer Points) OK, Ice Plains (FFA) NOT OK.
data.json
The heart of every NPC is its data.json
file. This file acts as a blueprint, defining every aspect of the NPC's appearance, behavior, and stats.
A fundamental choice you must make for every NPC is its physicsModel
. This property determines the core behavior and capabilities of your NPC. There are two primary types:
"stickman"
- The Humanoid NPCThis is the model you'll use for any NPC that acts like a character: walking, jumping, equipping items, and fighting with AI.
Key Characteristics:
skin
to be applied. The model
property must point to a valid skin ID (e.g., "model": "skins:5e73a1c0155817eca5e6bd5a"
).stickmanEquipment
object.ai
object, which defines how they target enemies and engage in combat.stickman_sword
, stickman_ninja
"item"
- The Object NPCThis model is for NPCs that behave more like objects or environmental hazards. They don't have complex AI but are often used to create an area-of-effect, a trap, or a static entity.
Key Characteristics:
model
property is a simple string that refers to an asset key (e.g., "model": "black_hole"
). This asset must be loaded by the game.stats
, such as duration
, invincibility
, attractionRadius
, and attractionForce
.ai
object.black_hole
, totem_healing
Now, let's dive into the detailed properties available in data.json
.
data.json
)This section details all the properties you can use in your NPC's data.json
file.
_id
: A unique identifier for the NPC. You can generate one, but the game will assign one if it's missing.version
: A version number for your NPC (e.g., "1.0.0"
). Crucially, you must increment this number for the server to recognize any changes you've made after it has loaded the NPC once. If your changes aren't appearing, this is the first thing to check.name
: An object containing the name of the NPC in different languages.fr
: French name.en
: English name.model
: Defines the visual appearance of the NPC.physicsModel: "stickman"
, this must be a reference to a skin ID (e.g., "model": "skins:5e73a1c0155817eca5e6bd5a"
).physicsModel: "item"
, this is an asset key for the sprite (e.g., "model": "black_hole"
).physicsModel
: The most important property. Determines the NPC's fundamental type. Can be "stickman"
or "item"
.available
: A boolean (true
or false
). If false
, this NPC will not be loaded by the game.physicsRect
: Defines the physical hitbox of the NPC.width
: The width of the hitbox in pixels (used for projectile detection). Usually 40
for a Stickman NPC.height
: The height of the hitbox in pixels (used for projectile detection). Usually 110
for a Stickman NPC.pathfindingWidth
: The width used for pathfinding system. A small value means that the NPC can go in holes and small areas more easily. Minimum is 32
and that is the value recommended for Stickman NPC.pathfindingHeight
: The width used for pathfinding system. A small value means that the NPC can go in holes and small areas more easily. Minimum is 32
. Value recommended for Stickman NPC is 80.
If the value is too high, the stickman will tend to levitate, and won't be able to go in tight space. If the value is too small the stickman will tend to go into the ground visually, and you'll have to adjust using displayOffsetY, also if too small, the stickman won't be able to jump and climb the wall on the Forest Edge map.
displayOffsetY
: (Optional) A vertical offset in pixels to adjust the sprite's position relative to its hitbox. Useful for aligning visuals. Value recommended for Stickman NPC is -5
.collides
: An array of strings defining what the NPC can collide with. In most cases, this will be ["prop"]
to interact with the map geometry.team
: Determines the NPC's allegiance. "source"
means it will adopt the team of the player or entity that spawned it. Can be set to null
for neutral entities.targets
: An array of strings defining who the NPC can target."enemy"
: Targets opposing players/NPCs."ally"
: Targets friendly players/NPCs."local"
: Targets itself (rarely used for a NPC).aggroRange
: The distance in pixels at which a stickman
NPC will detect and move towards a target.movementSpeed
: The speed at which a stickman
NPC moves, in pixels per second.This object contains the primary numerical attributes of the NPC.
baseHp
: The base health of the NPC.duration
: For non-stickman NPCs, this is the lifetime of the object in milliseconds. After this time, it will be destroyed. (e.g., 4000
for a 4-second duration).invincibility
: A boolean. If true
, the NPC cannot be damaged.isFlying
: A boolean. If true
, the NPC is not affected by gravity.attractionRadius
: For object NPCs, this is the radius in pixels within which it will pull other entities.attractionForce
: The strength of the pull for entities within the attractionRadius
.These properties only apply if physicsModel
is set to "stickman"
.
ai
: This object controls the Artificial Intelligence of the stickman.behavior
: The core behavior pattern. "attack_nearest_enemy"
is the most common. That's the only value available for now.targetPriorityDistance
: Seems to be a legacy or specialized property. aggroRange
is the primary detection radius.optimalDistanceFromTargetToAttack
: The ideal distance in pixels the NPC tries to maintain from its target while attacking.optimalDistanceFromTargetToAttackRandomness
: Adds a random variance to the optimal attack distance, making movement less predictable.optimalAngleAttackDegreesRandomness
: Adds a random offset (in degrees) to the NPC's attack angle, making its aim less perfect. To avoid the AIM BOT effect, use a value ≥ 8
.stickmanEquipment
: This object defines the items the NPC will use. The values are the IDs of items from the items
directory.weapon
: The primary weapon item ID.weaponModel
: The model name of the weapon, which must match the item's model
property.headgear
: The headgear item ID.throwable
: The throwable item ID.These properties are primarily for item
physics models but can sometimes affect stickmen.
hasParticles
: A boolean. If true
, the NPC will emit its associated particle effect while active.hasProcessingSound
: A boolean. If true
, the NPC will play a looping sound while active.hasDieParticles
: A boolean. If true
, a particle effect will be shown when the NPC is destroyed.hasDieSound
: A boolean. If true
, a sound will be played when the NPC is destroyed.spriteScale
: A number to scale the sprite's size (e.g., 0.7
for 70% of original size).angularVelocity
: The speed at which the NPC's sprite will rotate.actionTriggers
: An array that can make an NPC use an item automatically. This is powerful for creating NPCs that cast abilities.item
: The ID of the item to use.displayItem
: A boolean for whether the item's sprite should be visible.triggerDelayAfterSpawning
: The delay in milliseconds after the NPC spawns before it uses the item.killReward
: An object defining the rewards players receive for defeating this NPC.xp
: Experience pointscoins
: In-game currencydiamonds
: Premium currencyisShared
: A boolean. If true
, the reward is split among all players who contributed to the kill.Let's walk through creating a basic humanoid NPC. We will create a simple warrior that attacks enemies.
First, you need to create a new folder for your NPC inside your mod's npcs
directory. The folder name should be descriptive. For our example, let's call it my_warrior
.
/mods
/your_mod_name
/npcs
/my_warrior <-- Create this folder
data.json
FileInside the my_warrior
folder, create a new file named data.json
. This is where you'll define your NPC.
/mods
/your_mod_name
/npcs
/my_warrior
data.json <-- Create this file
data.json
Now, let's add the necessary configuration to your data.json
. The following is a minimal setup for a functional warrior NPC, based on the stickman_sword
example.
{
"version": "1.0.0",
"name": {
"fr": "Guerrier",
"en": "Warrior"
},
"model": "skins:5e73a1c0155817eca5e6bd5a",
"physicsModel": "stickman",
"physicsRect": {
"displayOffsetY": -5,
"width": 40,
"height": 110,
"pathfindingWidth": 32,
"pathfindingHeight": 80
},
"ai": {
"optimalDistanceFromObjective": 50,
"optimalDistanceFromTargetToAttack": 40,
"optimalDistanceFromTargetToAttackRandomness": 0,
"targetPriorityDistance": 150,
"optimalAngleAttackDegreesRandomness": 10,
"behavior": "attack_nearest_enemy"
},
"stickmanEquipment": {
"weapon": "5f23e8f9ede21004da63a274",
"weaponModel": "short_sword"
},
"stats": {
"baseHp": 500
},
"targets": [
"enemy"
],
"collides": [
"prop"
],
"movementSpeed": 250,
"aggroRange": 800,
"team": "source",
"available": true
}
What does this do?
model
).stickman
that can walk and fight.attack_nearest_enemy
within an aggroRange
of 800 pixels.short_sword
(using the item's ID for weapon
and its model name for weaponModel
).For a stickman
NPC, you don't need to provide any new graphical assets in the NPC's folder itself. All the visuals are handled by:
model
property points to an existing skin. The game will automatically load this skin and apply it to the NPC.stickmanEquipment
points to existing items. The game will load these items and attach them to the NPC.If you wanted to create a custom look, you would first need to create a new skin and new items, and then reference their IDs here.
To see your new NPC in the game, you will need to:
spawnNpcs
property, which we cover in the advanced section.data.json
file as needed. Remember to increment the version
number (e.g., from "1.0.0"
to "1.0.1"
) every time you make a change, otherwise the server will use a cached version of your NPC and you won't see your updates.This covers the basics of creating a humanoid NPC. Next, we will cover how to create an object-based NPC.
Now let's create an object-based NPC. These are simpler than humanoids and are great for creating things like traps, buffs, or environmental hazards. We will create a simple gravity well, inspired by the blackhole
example. You can also check the totem_fire
from Stickforge official mod.
As before, create a new folder for your NPC in your mod's npcs
directory. Let's call it my_gravity_well
.
For object NPCs, you also need to provide assets. It's good practice to place your assets within your npcs folder.
/mods
/your_mod_name
/assets
/npcs
/my_gravity_well <-- Create this folder and place your image here
my_gravity_well_model.png <-- Create this file, this is the sprite of your NPC
my_gravity_well_particles.json <-- Create this file, this is the particles of your NPC, can be generated using the particles editor
my_gravity_well_processing.ogg <-- Create this file, this is the processing sound
data.json
FileInside the my_gravity_well
folder, create the data.json
file.
/mods
/your_mod_name
/npcs
/my_gravity_well
data.json <-- Create this file
my_gravity_well_model.png
my_gravity_well_particles.json
my_gravity_well_processing.ogg
data.json
Here is a minimal configuration for our gravity well.
{
"version": "1.0.0",
"name": {
"fr": "Puits de Gravité",
"en": "Gravity Well"
},
"model": "my_gravity_well",
"physicsModel": "item",
"physicsRect": {
"width": 50,
"height": 50
},
"stats": {
"baseHp": 1,
"duration": 5000,
"invincibility": true,
"isFlying": true,
"attractionRadius": 200,
"attractionForce": 0.04
},
"targets": [
"enemy"
],
"collides": [],
"team": "source",
"available": true,
"hasParticles": true,
"spriteScale": 0.8
}
What does this do?
model
). The name "my_gravity_well"
must match the asset key you define when loading your assets.physicsModel
is "item"
, so it has no complex AI.stats
. It lasts for 5 seconds (duration
), is indestructible (invincibility
), and pulls enemies (targets
) within a 200-pixel radius.collides": []
), allowing it to be placed anywhere. Note: This property is not used for now.Testing is the same as with a humanoid NPC:
spawnNpcs
property.version
in data.json
to see your changes.Now that you know how to create the two basic types of NPCs, we can explore some more advanced concepts.
The most common way to bring your NPC into the game world is by having an item spawn it. This is done via the spawnNpcs
property in an item's data.json
file.
The spawnNpcs
property is an array, meaning a single item can spawn multiple different NPCs. Each entry in the array is an object that defines the rules for spawning.
Let's imagine we have an item—a "Gravity Bomb"—and we want it to spawn the my_gravity_well
NPC we created earlier.
Here's what the data.json
for our item might look like:
{
"_id": { "$oid": "YOUR_ITEM_ID" },
"version": "1.0.0",
"name": { "en": "Gravity Bomb" },
"model": "gravity_bomb_model",
"category": "throwables",
"stats": {
// ... other item stats
},
"spawnNpcs": [
{
"npc": "ID_OF_YOUR_NPC",
"triggerOn": "hit",
"chance": 1.0,
"maxInstances": 1
}
]
}
Let's break down the spawnNpcs
object:
npc
: This is the most important field. It must be the _id
of the NPC you want to spawn. For our example, you would replace "ID_OF_YOUR_NPC"
with the actual _id
from your my_gravity_well/data.json
.triggerOn
: This string determines when the spawn occurs. Available values include:"hit"
: Spawns when the projectile hits a player."cast"
: Spawns immediately when the player uses the item.chance
: A number between 0.0
and 1.0
representing the probability of the spawn occurring. 1.0
means it will always spawn, 0.5
means a 50% chance.maxInstances
: An integer that limits how many of this specific NPC, spawned by this specific player, can exist at one time. If the limit is 1
and the player uses the item again, the old NPC will be destroyed and a new one will be created.By using this structure, you can create powerful items that introduce complex behaviors into the game by spawning your custom NPCs.