-
Notifications
You must be signed in to change notification settings - Fork 2
API Spawn Flags
Spawn flags are bit flags set in map editors (like TrenchBroom or NetRadiant) that control entity behavior at spawn time. They are defined throughout the codebase but primarily in src/baseq2rtxp/svgame/entities/svg_base_edict.h and individual entity headers.
Spawn flags allow level designers to customize entity behavior without coding. They are set using checkboxes in map editors and are stored in the spawnflags member of svg_base_edict_t.
Key Characteristics:
- Set at map load time: Flags are read from map entity definitions
- Bitmask values: Multiple flags can be combined using bitwise OR
- Read-only at runtime: Typically not changed after spawn
- Editor-friendly: Exposed as checkboxes in map editors
These flags are available for all entities and defined in src/baseq2rtxp/svgame/entities/svg_base_edict.h:
static constexpr spawnflag_t SPAWNFLAG_NOT_DEATHMATCH = BIT(19); // Bit 19
static constexpr spawnflag_t SPAWNFLAG_NOT_COOP = BIT(20); // Bit 20Purpose: Exclude entities from specific game modes
Usage in Maps:
// In .map file
{
"classname" "weapon_shotgun"
"origin" "128 256 64"
"spawnflags" "524288" // SPAWNFLAG_NOT_DEATHMATCH (2^19)
}
Server-side Check:
void svg_base_edict_t::Spawn() {
// Check if entity should spawn in current game mode
if (game.deathmatch && (spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) {
SVG_FreeEdict(this);
return;
}
if (game.coop && (spawnflags & SPAWNFLAG_NOT_COOP)) {
SVG_FreeEdict(this);
return;
}
// Continue spawning...
}Example Use Cases:
- Health packs only in single-player/coop
- Extra ammo only in deathmatch
- Story-specific entities excluded from multiplayer
static constexpr spawnflag_t SPAWNFLAG_NOT_EASY = BIT(21); // Bit 21
static constexpr spawnflag_t SPAWNFLAG_NOT_MEDIUM = BIT(22); // Bit 22
static constexpr spawnflag_t SPAWNFLAG_NOT_HARD = BIT(23); // Bit 23Purpose: Exclude entities from specific difficulty levels
Usage:
void svg_monster_soldier_t::Spawn() {
// Check difficulty level
int skill_level = (int)g_skill->value;
if (skill_level == 0 && (spawnflags & SPAWNFLAG_NOT_EASY)) {
SVG_FreeEdict(this);
return;
}
if (skill_level == 1 && (spawnflags & SPAWNFLAG_NOT_MEDIUM)) {
SVG_FreeEdict(this);
return;
}
if (skill_level >= 2 && (spawnflags & SPAWNFLAG_NOT_HARD)) {
SVG_FreeEdict(this);
return;
}
// Spawn monster...
}Example Use Cases:
- Fewer monsters on easy difficulty
- Extra monsters on hard difficulty
- Powerful weapons only on higher difficulties
static constexpr spawnflag_t SPAWNFLAG_USETARGET_DISABLED = BIT(15); // Bit 15
static constexpr spawnflag_t SPAWNFLAG_USETARGET_PRESSABLE = BIT(16); // Bit 16
static constexpr spawnflag_t SPAWNFLAG_USETARGET_TOGGLEABLE = BIT(17); // Bit 17
static constexpr spawnflag_t SPAWNFLAG_USETARGET_HOLDABLE = BIT(18); // Bit 18Purpose: Control interactive behavior with the use key
Temporarily disables use-key interaction for this entity.
void svg_base_edict_t::CheckUseTarget(svg_player_edict_t *player) {
if (spawnflags & SPAWNFLAG_USETARGET_DISABLED) {
return; // Cannot be used
}
// Allow use...
}Use Case: Buttons or switches that start disabled and activate via trigger
Entity acts as a button - single press activates.
void svg_func_button_t::Spawn() {
spawnflags |= SPAWNFLAG_USETARGET_PRESSABLE;
// Set up button behavior...
}Use Case: Buttons, switches, levers
Entity toggles between on/off states with each use.
void svg_func_door_t::UseTarget_OnPress(svg_base_edict_t *other) {
if (spawnflags & SPAWNFLAG_USETARGET_TOGGLEABLE) {
if (moveinfo.state == STATE_TOP) {
// Door is open, close it
Close();
} else if (moveinfo.state == STATE_BOTTOM) {
// Door is closed, open it
Open();
}
}
}Use Case: Doors that toggle, lights that switch on/off
Entity responds to hold duration - triggers on press and release.
void svg_func_train_t::UseTarget_OnPress(svg_base_edict_t *other) {
if (spawnflags & SPAWNFLAG_USETARGET_HOLDABLE) {
// Start moving
StartMoving();
}
}
void svg_func_train_t::UseTarget_OnRelease(svg_base_edict_t *other) {
if (spawnflags & SPAWNFLAG_USETARGET_HOLDABLE) {
// Stop moving
StopMoving();
}
}Use Case: Elevators, cranes, hold-to-activate mechanisms
Location: src/baseq2rtxp/svgame/entities/trigger/svg_trigger_multiple.h
static constexpr spawnflag_t SPAWNFLAG_MONSTER = 1; // Bit 0
static constexpr spawnflag_t SPAWNFLAG_NOT_PLAYER = 2; // Bit 1
static constexpr spawnflag_t SPAWNFLAG_TRIGGERED = 4; // Bit 2
static constexpr spawnflag_t SPAWNFLAG_BRUSH_CLIP = 32; // Bit 5SPAWNFLAG_MONSTER:
void svg_trigger_multiple_t::Touch(svg_base_edict_t *other) {
if (spawnflags & SPAWNFLAG_MONSTER) {
if (!(other->svflags & SVF_MONSTER))
return; // Only monsters can trigger
}
}SPAWNFLAG_NOT_PLAYER:
void svg_trigger_multiple_t::Touch(svg_base_edict_t *other) {
if ((spawnflags & SPAWNFLAG_NOT_PLAYER) && other->client)
return; // Players cannot trigger this
}SPAWNFLAG_TRIGGERED:
void svg_trigger_multiple_t::Spawn() {
if (spawnflags & SPAWNFLAG_TRIGGERED) {
solid = SOLID_NOT; // Start inactive
// Requires Use() call to activate
}
}Location: src/baseq2rtxp/svgame/entities/trigger/svg_trigger_hurt.h
static constexpr int32_t SPAWNFLAG_START_OFF = 1; // Bit 0
static constexpr int32_t SPAWNFLAG_TOGGLE = 2; // Bit 1
static constexpr int32_t SPAWNFLAG_SILENT = 4; // Bit 2
static constexpr int32_t SPAWNFLAG_NO_PROTECTION = 8; // Bit 3
static constexpr int32_t SPAWNFLAG_SLOW_HURT = 16; // Bit 4
static constexpr int32_t SPAWNFLAG_BRUSH_CLIP = 32; // Bit 5Examples:
// Start inactive
if (spawnflags & SPAWNFLAG_START_OFF) {
solid = SOLID_NOT;
}
// Toggle on/off via Use()
if (spawnflags & SPAWNFLAG_TOGGLE) {
// Allow toggling between active/inactive
}
// No pain sounds
if (spawnflags & SPAWNFLAG_SILENT) {
// Don't play damage sounds
}
// Ignore armor
if (spawnflags & SPAWNFLAG_NO_PROTECTION) {
damage_flags |= DAMAGE_NO_ARMOR;
}
// Damage once per second instead of 10 times per second
if (spawnflags & SPAWNFLAG_SLOW_HURT) {
timestamp = level.time + 1.0;
}Location: src/baseq2rtxp/svgame/entities/trigger/svg_trigger_push.h
static constexpr spawnflag_t SPAWNFLAG_PUSH_ONCE = 1; // Bit 0
static constexpr spawnflag_t SPAWNFLAG_BRUSH_CLIP = 32; // Bit 5SPAWNFLAG_PUSH_ONCE:
void svg_trigger_push_t::Touch(svg_base_edict_t *other) {
// Apply push velocity
other->velocity = push_velocity;
if (spawnflags & SPAWNFLAG_PUSH_ONCE) {
// Remove after first use
SVG_FreeEdict(this);
}
}Location: src/baseq2rtxp/svgame/entities/trigger/svg_trigger_gravity.h
static constexpr spawnflag_t SPAWNFLAG_TOGGLE = 8; // Bit 3
static constexpr spawnflag_t SPAWNFLAG_START_OFF = 16; // Bit 4
static constexpr spawnflag_t SPAWNFLAG_BRUSH_CLIP = 32; // Bit 5Location: src/baseq2rtxp/svgame/entities/light/svg_light_light.h
static constexpr spawnflag_t SPAWNFLAG_START_OFF = 1; // Bit 0Usage:
void svg_light_light_t::Spawn() {
if (spawnflags & SPAWNFLAG_START_OFF) {
s.renderfx |= RF_SHELL_RED; // Light starts off
} else {
s.renderfx |= RF_SHELL_GREEN; // Light starts on
}
}
void svg_light_light_t::Use(svg_base_edict_t *other) {
// Toggle light on/off
if (s.renderfx & RF_SHELL_GREEN) {
s.renderfx &= ~RF_SHELL_GREEN;
s.renderfx |= RF_SHELL_RED;
} else {
s.renderfx &= ~RF_SHELL_RED;
s.renderfx |= RF_SHELL_GREEN;
}
}Location: src/baseq2rtxp/svgame/entities/target/svg_target_laser.h
static constexpr spawnflag_t SPAWNFLAG_START_ON = BIT(0); // Bit 0
static constexpr spawnflag_t SPAWNFLAG_COLOR_RED = BIT(1); // Bit 1
static constexpr spawnflag_t SPAWNFLAG_COLOR_GREEN = BIT(2); // Bit 2
static constexpr spawnflag_t SPAWNFLAG_COLOR_BLUE = BIT(3); // Bit 3
static constexpr spawnflag_t SPAWNFLAG_COLOR_YELLOW = BIT(4); // Bit 4
static constexpr spawnflag_t SPAWNFLAG_COLOR_ORANGE = BIT(5); // Bit 5
static constexpr spawnflag_t SPAWNFLAG_THICK = BIT(6); // Bit 6Color Selection:
void svg_target_laser_t::Spawn() {
if (spawnflags & SPAWNFLAG_COLOR_RED) {
s.skinnum = 0xf2f2f0f0;
} else if (spawnflags & SPAWNFLAG_COLOR_GREEN) {
s.skinnum = 0xd0d1d2d3;
} else if (spawnflags & SPAWNFLAG_COLOR_BLUE) {
s.skinnum = 0xf3f3f1f1;
} else if (spawnflags & SPAWNFLAG_COLOR_YELLOW) {
s.skinnum = 0xdcdddedf;
} else if (spawnflags & SPAWNFLAG_COLOR_ORANGE) {
s.skinnum = 0xe0e1e2e3;
}
if (spawnflags & SPAWNFLAG_THICK) {
s.frame = 16; // Thicker laser beam
} else {
s.frame = 4; // Normal laser beam
}
}Location: src/baseq2rtxp/svgame/entities/trigger/svg_trigger_counter.h
static constexpr spawnflag_t SPAWNFLAG_NO_MESSAGE = BIT(0); // Bit 0
static constexpr spawnflag_t SPAWNFLAG_TOUCHABLE = 64; // Bit 6SPAWNFLAG_NO_MESSAGE:
void svg_trigger_counter_t::Use(svg_base_edict_t *activator) {
count--;
if (count > 0 && !(spawnflags & SPAWNFLAG_NO_MESSAGE)) {
// Display counter message
gi.centerprintf(activator, "%i more to go...", count);
}
}// Check single flag
if (spawnflags & SPAWNFLAG_NOT_DEATHMATCH) {
// Entity excluded from deathmatch
}
// Check multiple flags (any)
if (spawnflags & (SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM)) {
// Entity excluded from easy OR medium
}
// Check multiple flags (all)
if ((spawnflags & (FLAG_A | FLAG_B)) == (FLAG_A | FLAG_B)) {
// Entity has BOTH flags set
}// Add a flag
spawnflags |= SPAWNFLAG_START_OFF;
// Remove a flag
spawnflags &= ~SPAWNFLAG_START_OFF;
// Toggle a flag
spawnflags ^= SPAWNFLAG_TOGGLE;Note: Typically spawn flags are read-only after spawn and shouldn't be modified at runtime unless you have a specific reason.
When creating custom entities, define spawn flags as class-specific constants:
// In your custom entity header
class svg_custom_trigger_t : public svg_trigger_multiple_t {
public:
// Custom spawn flags
static constexpr spawnflag_t SPAWNFLAG_REVERSE = BIT(10);
static constexpr spawnflag_t SPAWNFLAG_RANDOM = BIT(11);
void Spawn() override {
if (spawnflags & SPAWNFLAG_REVERSE) {
// Custom behavior
}
if (spawnflags & SPAWNFLAG_RANDOM) {
// More custom behavior
}
// Call parent spawn
svg_trigger_multiple_t::Spawn();
}
};Bit Usage Guidelines:
- Bits 0-14: Entity-specific flags
- Bit 15-18: UseTarget system (universal)
- Bits 19-23: Game mode/difficulty filters (universal)
- Bits 24-31: Available for custom use
@PointClass base(Targetname) = trigger_hurt : "Hurt Trigger"
[
spawnflags(flags) =
[
1 : "Start Off" : 0
2 : "Toggle" : 0
4 : "Silent" : 0
8 : "No Protection" : 0
16 : "Slow Hurt" : 0
]
dmg(integer) : "Damage" : 5
wait(string) : "Wait" : "1"
]
<point name="trigger_hurt" color="1 .5 .5" box="-8 -8 -8 8 8 8">
Hurts entities that touch it.
-------- KEYS --------
dmg : damage to deal (default 5)
-------- SPAWNFLAGS --------
1 : START_OFF - trigger starts disabled
2 : TOGGLE - can be toggled on/off
4 : SILENT - no damage sounds
8 : NO_PROTECTION - ignores armor
16 : SLOW_HURT - damage once per second
</point>
✅ Use spawn flags for:
- Game mode filtering (deathmatch vs. coop)
- Difficulty scaling
- Initial state (on/off, open/closed)
- Behavior variations (toggle vs. momentary)
- Visual variations (colors, sizes)
❌ Don't use spawn flags for:
- Runtime state changes (use member variables)
- Complex logic (use entity keys/properties)
- Data that changes frequently
// GOOD: Clear, descriptive names
static constexpr spawnflag_t SPAWNFLAG_START_OFF = BIT(0);
static constexpr spawnflag_t SPAWNFLAG_TOGGLE = BIT(1);
// BAD: Cryptic names
static constexpr spawnflag_t SF1 = BIT(0);
static constexpr spawnflag_t FLAG_A = BIT(1);Always document spawn flags in:
- Code comments - What the flag does
- Entity headers - Grouped with related flags
- Map editor definitions - FGD/DEF files
- Wiki pages - Usage examples
- Entity System Overview - Entity architecture
- Creating Custom Entities - Implementing spawn flags
- UseTargets System - UseTarget spawn flags in detail
- Server Game Module - Entity spawning system
- API - Entity Types - Entity type reference
- API - Entity Flags - Runtime entity flags (different from spawn flags)
Spawn flags are design-time bit flags that control entity behavior:
- Set in map editors using checkboxes
- Read at spawn time from map entity data
- Bitmask values allow multiple flags per entity
- Universal flags (bits 15-23) work on all entities
- Entity-specific flags (bits 0-14, 24-31) for custom behavior
Use spawn flags to give level designers control over entity behavior without requiring code changes. Keep flags simple, well-documented, and exposed in map editor definitions.