Skip to content

Custom enemies

Custom enemies are a clone-and-patch kind: you start from a vanilla enemy, change its stats/assets, and register it as a new definition. Confirmed

The enemy kind is confirmed, so no experimental opt-in is needed.

build.py
from rsmm import sdk
with sdk.Mod("MyEnemies") as mod:
mod.enemy(
"Frost_Goblin",
base="Goblins/Goblin_Warrior", # vanilla donor to clone
name="Frost Goblin",
# **fields override stat-block values on the clone
)

Equivalent declarative form:

mods/MyEnemies/manifest.toml
[mod]
id = "MyEnemies"
[[content]]
kind = "enemy"
id = "Frost_Goblin"
base = "Goblins/Goblin_Warrior"
name = "Frost Goblin"

Mod.boss(...) takes the same shape. Bosses are not a separate class — they are ordinary enemies tagged into the boss flag-list and gated by the boss-timer controller.

Run ./rsmm apply to cook and register the definition.

Spawning is selector-driven, not a direct “place enemy X” call. The chain:

flowchart LR
    E["oCDtEnemyDefinition<br/>(one stat block)"] --> T["oCDtEnemyTribeDefinition<br/>(group / faction)"]
    T --> S["Camp spawn selector<br/>(flag-list, tag-filtered)"]
    C["oCDtEnemyCampTierDefinition<br/>(camp difficulty tier)"] --> S
    S --> R["runtime spawn in a camp"]

An enemy reaches a run by being a member of a tribe, which a camp selector picks via tags/flags at the right difficulty tier. So registering a definition is necessary but not sufficient — something must select it.

The full camp/enemy machinery, for when you need the internals:

Class UID Library Purpose
oCDtEnemyDefinition 0x176debb7 0x1414118c0 one enemy stat block
oCDtEnemyTribeDefinition — 0x141411200 tribe = group / faction
oCDtEnemyCampTierDefinition 0x176e18f8 0x141411560 difficulty tier of one camp
oCDtEnemyCampDifficultyDefinition — 0x141411710 global difficulty curve
oCDtEnemyCampEntitySelectorToSpawnEntityCpntSettings 0x16b7d175 — per-camp spawn selector
oCDtEnemyCampEntitySelectorToSpawnTribeEntrySettings 0x16b81d80 — one tribe entry inside a camp
oCDtEnemyFlagListEntitySelectorToSpawnEntityCpntSettings 0x17019bf9 — tag-filtered enemy selector

oCDtEnemyDefinition is fully registered (size 0x350, factory FUN_14030a190). The runtime spawn primitive itself — the vftable[3] call that constructs an entity at a position — is documented in Spawning.