-
Notifications
You must be signed in to change notification settings - Fork 2
API Entity Flags
Entity flags control special behaviors and rendering effects. They are defined in src/baseq2rtxp/sharedgame/sg_entity_flags.h.
Entity flags (entity_state_t::effects) are bit flags sent to clients that control visual effects and entity behavior. They're applied using bitwise operations.
Location: src/baseq2rtxp/sharedgame/sg_entity_flags.h
These flags control how entities are rendered on the client:
#define EF_ROTATE BIT(1) // Rotate (bonus items)
#define EF_GIB BIT(2) // Leave a trail (blood)
#define EF_ANIM_CYCLE2_2HZ BIT(3) // Cycle frames 0-1 at 2 Hz
#define EF_ANIM01 BIT(4) // Cycle frames 0-1 at 2 Hz
#define EF_ANIM23 BIT(5) // Cycle frames 2-3 at 2 Hz
#define EF_ANIM_ALL BIT(6) // Cycle all frames at 2 Hz
#define EF_ANIM_ALLFAST BIT(7) // Cycle all frames at 10 HzThese flags indicate active power-ups:
#define EF_COLOR_SHELL BIT(8) // Colored shell effect
#define EF_QUAD BIT(9) // Quad damage glow
#define EF_PENT BIT(10) // Pentagram of protection
#define EF_DOUBLE BIT(11) // Double damage
#define EF_HALF_DAMAGE BIT(12) // Half damage taken#define EF_TELEPORTER BIT(13) // Teleporter particle fountain#define EF_ENTITY_EVENT_TARGET_OTHER BIT(14) // Event targets another entity#define EF_UNUSED_15 through EF_UNUSED_31 // Available for custom useMake pickup items spin:
void svg_item_health_t::Spawn() {
s.effects |= EF_ROTATE; // Item rotates continuously
s.entityType = ET_ITEM;
}Client Behavior: Item rotates around Z-axis at constant speed
Create blinking or animated lights:
void svg_light_blink_t::Spawn() {
s.effects |= EF_ANIM01; // Blink between frames 0 and 1
}
void svg_light_strobe_t::Spawn() {
s.effects |= EF_ANIM_ALLFAST; // Fast animation through all frames
}Frame Cycling Speeds:
-
EF_ANIM01,EF_ANIM23,EF_ANIM_ALL: 2 Hz (2 cycles per second) -
EF_ANIM_ALLFAST: 10 Hz (10 cycles per second)
Make gibs leave blood trails:
void SVG_ThrowGib(/*...*/) {
gib->s.effects |= EF_GIB; // Leaves blood particle trail
gib->movetype = MOVETYPE_BOUNCE;
}Client Behavior: Spawns blood particles along movement path
Indicate active power-ups on players:
void svg_player_edict_t::PickupQuad() {
s.effects |= EF_QUAD; // Blue glow
// Stacks with other effects
}
void svg_player_edict_t::PickupInvulnerability() {
s.effects |= EF_PENT; // Red glow
}Visual Effects:
-
EF_QUAD: Blue outer glow -
EF_PENT: Red spinning shell -
EF_DOUBLE: Green glow -
EF_HALF_DAMAGE: Yellow glow
Note: These can be combined (bitwise OR) for multiple simultaneous effects.
Custom colored shells around entities:
void svg_player_edict_t::ApplyColorShell(vec3_t color) {
s.effects |= EF_COLOR_SHELL;
s.renderfx = RF_SHELL_RED | RF_SHELL_GREEN; // Yellow shell
}Requires: Also setting renderfx flags for shell colors
Spawn particle fountain effect:
void svg_misc_teleporter_t::Spawn() {
s.effects |= EF_TELEPORTER; // Upward particle stream
}Client Behavior: Continuous upward particle fountain
Flags are combined using bitwise OR (|):
// Item that rotates and has animation
s.effects = EF_ROTATE | EF_ANIM_ALL;
// Player with quad damage and invulnerability
s.effects = EF_QUAD | EF_PENT;
// Gib that leaves trail and rotates
s.effects = EF_GIB | EF_ROTATE;// Add flag (preserves other flags)
s.effects |= EF_ROTATE;
// Set multiple flags
s.effects |= (EF_ROTATE | EF_ANIM_ALL);// Remove flag (preserves other flags)
s.effects &= ~EF_ROTATE;
// Remove multiple flags
s.effects &= ~(EF_ROTATE | EF_ANIM_ALL);// Toggle on/off
s.effects ^= EF_ANIM01;
// Example: Blinking light
void Think() {
s.effects ^= EF_ANIM01; // Toggle between on and off
nextThinkTime = level.time + gametime_t::from_sec(0.5f);
}// Check if flag is set
if (s.effects & EF_ROTATE) {
gi.dprintf("Entity is rotating\n");
}
// Check multiple flags (any)
if (s.effects & (EF_QUAD | EF_PENT)) {
gi.dprintf("Has power-up\n");
}
// Check multiple flags (all)
if ((s.effects & (EF_QUAD | EF_PENT)) == (EF_QUAD | EF_PENT)) {
gi.dprintf("Has both quad and pent\n");
}The client uses these flags to control rendering:
// In client rendering code (clgame)
void CLG_AddEntity(centity_t *cent) {
entity_t ent = {};
// Check for rotation
if (cent->current.effects & EF_ROTATE) {
ent.angles[YAW] = anglemod(cl.time * 100); // Rotate
}
// Check for animation
if (cent->current.effects & EF_ANIM01) {
int frame = (cl.time / 500) & 1; // Alternate 0,1 at 2 Hz
ent.frame = frame;
}
// Check for trails
if (cent->current.effects & EF_GIB) {
CLG_AddGibTrail(cent); // Blood particles
}
// Check for power-up glows
if (cent->current.effects & EF_QUAD) {
CLG_AddQuadGlow(&ent); // Blue glow
}
V_AddEntity(&ent);
}void svg_item_bonus_t::Spawn() {
// Rotating, animated item
s.effects = EF_ROTATE | EF_ANIM_ALLFAST;
s.entityType = ET_ITEM;
gi.SetModel(edict, "models/items/bonus/tris.md2");
}Result: Item spins and cycles through animation frames rapidly
class svg_light_strobe_t : public svg_base_edict_t {
void Spawn() override {
s.effects = EF_ANIM01;
SetThinkCallback(&svg_light_strobe_t::StrobeThink);
nextThinkTime = level.time + FRAMETIME;
}
void StrobeThink() {
// Toggle light on/off
s.effects ^= EF_ANIM01;
nextThinkTime = level.time + gametime_t::from_sec(0.1f);
}
};Result: Light blinks rapidly (10 Hz)
void svg_player_edict_t::UpdatePowerUps() {
// Clear old power-up flags
s.effects &= ~(EF_QUAD | EF_PENT | EF_DOUBLE | EF_HALF_DAMAGE);
// Apply active power-ups
if (client->quad_framenum > level.frameNumber) {
s.effects |= EF_QUAD;
}
if (client->invincible_framenum > level.frameNumber) {
s.effects |= EF_PENT;
}
if (client->double_framenum > level.frameNumber) {
s.effects |= EF_DOUBLE;
}
}Result: Player glows based on active power-ups
void svg_monster_soldier_t::Die(/*...*/) {
// Gib if overkill
if (health < gib_health) {
for (int i = 0; i < 4; i++) {
auto *gib = ThrowGib("models/objects/gibs/sm_meat/tris.md2", damage);
gib->s.effects |= EF_GIB; // Blood trail
}
}
}Result: Flying gibs leave blood particle trails
void svg_misc_teleporter_t::Spawn() {
s.effects = EF_TELEPORTER;
s.modelindex = gi.modelindex("models/objects/dmspot/tris.md2");
// Also play looping sound
s.sound = gi.soundindex("world/amb10.wav");
}Result: Pad has upward particle stream and ambient sound
You can use unused flags for custom effects:
// Define custom flag
#define EF_CUSTOM_GLOW EF_UNUSED_15
// Server-side
void svg_custom_entity_t::Spawn() {
s.effects |= EF_CUSTOM_GLOW;
}
// Client-side (in clgame)
void CLG_AddEntity(centity_t *cent) {
if (cent->current.effects & EF_CUSTOM_GLOW) {
CLG_AddCustomGlowEffect(cent); // Your custom rendering
}
}Note: Requires modifying both server and client code
Each flag set adds minimal overhead:
- Flags are part of entity state (always sent)
- Setting/clearing flags is bitwise operation (very fast)
- Client-side checks are also bitwise (very fast)
Some effects are more expensive than others:
Low Cost:
-
EF_ROTATE- Simple angle calculation -
EF_ANIM01- Frame index calculation
Medium Cost:
-
EF_GIB- Spawns particles periodically -
EF_TELEPORTER- Continuous particle spawning
High Cost:
-
EF_QUAD,EF_PENT- Additional rendering passes for glows -
EF_COLOR_SHELL- Outline rendering
Tip: Don't combine too many expensive effects on many entities
// Show entity effects
ent_info <entitynum>
// Output includes:
// Entity 5: monster_soldier
// effects: EF_ROTATE | EF_GIB
#ifdef _DEBUG
void DebugEntityEffects(svg_base_edict_t *ent) {
if (ent->s.effects & EF_ROTATE)
gi.dprintf(" EF_ROTATE\n");
if (ent->s.effects & EF_GIB)
gi.dprintf(" EF_GIB\n");
if (ent->s.effects & EF_QUAD)
gi.dprintf(" EF_QUAD\n");
// ... check all flags ...
}
#endif// In client game (clgame)
if (cl_show_effects->value) {
DrawText(va("Effects: 0x%04X", cent->current.effects));
}// BAD: Effects without model
s.effects = EF_ROTATE;
// Nothing to rotate!
// GOOD: Set model first
gi.SetModel(edict, "models/items/health/tris.md2");
s.effects = EF_ROTATE;// BAD: Overwrites existing effects
s.effects = EF_QUAD; // Loses EF_ROTATE if it was set
// GOOD: Add to existing effects
s.effects |= EF_QUAD; // Preserves other flags// BAD: Model doesn't have enough frames
s.effects = EF_ANIM_ALL; // But model only has 2 frames
// GOOD: Use appropriate animation
if (modelFrameCount <= 2) {
s.effects = EF_ANIM01; // Only use frames 0-1
}// When completely changing effect state
s.effects = 0; // Clear all
s.effects = EF_ROTATE | EF_ANIM_ALL; // Set new state// GOOD: Clear and maintainable
static constexpr uint32_t POWERUP_FLAGS = EF_QUAD | EF_PENT | EF_DOUBLE;
void ClearPowerUps() {
s.effects &= ~POWERUP_FLAGS;
}// If using unused flags, document them
// EF_UNUSED_15: Custom entity glow effect
// EF_UNUSED_16: Custom pulsing effect
#define EF_CUSTOM_GLOW EF_UNUSED_15
#define EF_CUSTOM_PULSE EF_UNUSED_16- Entity Types - Entity type constants
- Entity Events - Entity event system
- Entity System Overview - Entity architecture
- Client Game Module - Client-side rendering
See Also:
-
src/baseq2rtxp/sharedgame/sg_entity_flags.h- Flag definitions -
src/baseq2rtxp/clgame/clg_entities.cpp- Client rendering code -
src/baseq2rtxp/svgame/svg_spawn.cpp- Server entity spawning