-
Notifications
You must be signed in to change notification settings - Fork 3
UseTargets System
The UseTargets system allows entities to activate other entities through target/targetname relationships and player interaction.
Location: src/baseq2rtxp/svgame/svg_usetargets.h and player interaction code
UseTargets enables:
- Map entity targeting: Buttons trigger doors, triggers activate spawners
- Player interaction: Use key (+use) to interact with entities
- Entity chains: One entity activates multiple others
[Button] [Door]
target="door1" ----> targetname="door1"
Player presses button → Button activates door
Button entity:
{
"classname" "func_button"
"target" "door1"
"origin" "128 256 64"
}
Door entity:
{
"classname" "func_door"
"targetname" "door1"
"origin" "256 256 64"
}
Activating targets:
void svg_func_button_t::Use(svg_base_edict_t *other,
svg_base_edict_t *activator, /*...*/) {
// Button pressed, activate all entities with matching targetname
UseTargets(activator, activator);
}UseTargets implementation:
void svg_base_edict_t::UseTargets(svg_base_edict_t *other,
svg_base_edict_t *activator) {
if (!target)
return; // No target set
// Find all entities with matching targetname
svg_base_edict_t *t = nullptr;
while ((t = SVG_Find(t, FOFS(targetname), target)) != nullptr) {
// Activate each matching entity
t->Use(this, activator, ENTITY_USETARGET_TYPE_TOGGLE, 0);
}
}Players can interact with entities using the +use key (default: E).
Making an entity interactable:
void svg_func_door_t::Spawn() {
// ... door setup ...
// Make door useable
spawnflags |= SPAWNFLAG_USETARGET_PRESSABLE;
// Set Use callback
SetUseCallback(&svg_func_door_t::Use);
}
void svg_func_door_t::Use(svg_base_edict_t *other,
svg_base_edict_t *activator, /*...*/) {
// Player pressed use on door
if (moveinfo.state == STATE_BOTTOM) {
Door_GoUp(); // Open door
} else if (moveinfo.state == STATE_TOP) {
Door_GoDown(); // Close door
}
}typedef enum entity_usetarget_type_e {
ENTITY_USETARGET_TYPE_OFF, // Turn off
ENTITY_USETARGET_TYPE_ON, // Turn on
ENTITY_USETARGET_TYPE_SET, // Set to specific value
ENTITY_USETARGET_TYPE_TOGGLE // Toggle on/off
} entity_usetarget_type_t;Usage:
void Use(svg_base_edict_t *other, svg_base_edict_t *activator,
entity_usetarget_type_t useType, int32_t useValue) {
switch (useType) {
case ENTITY_USETARGET_TYPE_ON:
TurnOn();
break;
case ENTITY_USETARGET_TYPE_OFF:
TurnOff();
break;
case ENTITY_USETARGET_TYPE_TOGGLE:
if (is_on) TurnOff(); else TurnOn();
break;
}
}Spawn flags:
SPAWNFLAG_USETARGET_DISABLED // Can't be used (temporarily)
SPAWNFLAG_USETARGET_PRESSABLE // Single press activates
SPAWNFLAG_USETARGET_TOGGLEABLE // Press toggles on/off
SPAWNFLAG_USETARGET_HOLDABLE // Hold to activate continuouslyExample - Holdable button:
void svg_func_train_t::Spawn() {
spawnflags |= SPAWNFLAG_USETARGET_HOLDABLE;
SetUseCallback(&svg_func_train_t::Use);
}
void svg_func_train_t::Use(/*...*/) {
// Called when player presses use
StartMoving();
}
void svg_func_train_t::UseRelease(/*...*/) {
// Called when player releases use
StopMoving();
}One entity can activate multiple targets:
Map:
Button target="light1;light2;light3"
→ Activates light1, light2, AND light3
Code:
void UseTargets(svg_base_edict_t *activator, svg_base_edict_t *other) {
// Tokenize target string by semicolon
const char *token = strtok(target, ";");
while (token) {
// Find entities with this targetname
svg_base_edict_t *t = nullptr;
while ((t = SVG_Find(t, FOFS(targetname), token)) != nullptr) {
t->Use(this, activator, ENTITY_USETARGET_TYPE_TOGGLE, 0);
}
token = strtok(NULL, ";");
}
}Special target that removes entities:
Map:
{
"classname" "trigger_multiple"
"killtarget" "monster1"
}
Code:
void UseTargets(/*...*/) {
// Kill targets
if (killtarget) {
svg_base_edict_t *t = nullptr;
while ((t = SVG_Find(t, FOFS(targetname), killtarget)) != nullptr) {
SVG_FreeEdict(t); // Remove entity
}
}
// Then activate normal targets
if (target) {
// ... normal target activation ...
}
}// Button
void svg_func_button_t::Use(/*...*/) {
// Button pressed
UseTargets(activator, activator); // Activate door
}
// Door
void svg_func_door_t::Use(/*...*/) {
// Triggered by button
if (useType == ENTITY_USETARGET_TYPE_ON ||
useType == ENTITY_USETARGET_TYPE_TOGGLE) {
Door_GoUp(); // Open
}
}// Trigger
void svg_trigger_multiple_t::Touch(svg_base_edict_t *other, /*...*/) {
if (!other->client)
return;
UseTargets(other, other); // Activate spawner
}
// Monster spawner
void svg_target_spawner_t::Use(/*...*/) {
// Spawn monster
auto *monster = SVG_Spawn<svg_monster_soldier_t>();
monster->s.origin = s.origin;
monster->Spawn();
}Display hints to players:
// In player code
void Check_UseTarget_Hints(svg_player_edict_t *player) {
// Trace forward from player
trace_t tr = TraceForward(player, 64.0f);
if (tr.ent && tr.ent->spawnflags & SPAWNFLAG_USETARGET_PRESSABLE) {
// Show "Press E to use" hint
player->client->ps.stats[STAT_USE_HINT] = CS_GENERAL + hint_index;
}
}// GOOD: Descriptive targetnames
"targetname" "security_door_1"
"targetname" "wave1_spawn_point"
// BAD: Generic names
"targetname" "door"
"targetname" "entity1"void PostSpawn() override {
// Warn if target doesn't exist
if (target && !SVG_Find(nullptr, FOFS(targetname), target)) {
gi.dprintf("WARNING: Entity %s targets non-existent '%s'\n",
classname, target);
}
}void Use(/*...*/) {
// Cooldown to prevent spamming
if (level.time < use_timestamp) {
return; // Too soon
}
UseTargets(activator, activator);
use_timestamp = level.time + 0.5f; // 0.5 second cooldown
}- Entity System Overview
- Creating Custom Entities
- Signal I/O System - Advanced entity communication
- API - Spawn Flags - UseTarget spawn flags
The UseTargets system provides entity interaction:
- target/targetname: Entity targeting relationships
- UseTargets(): Activates all entities with matching targetname
- Use callback: Player interaction with +use key
- Use types: ON, OFF, TOGGLE, SET
- Spawn flags: PRESSABLE, TOGGLEABLE, HOLDABLE
- killtarget: Remove entities
This system is fundamental to creating interactive maps and gameplay in Q2RTXPerimental. Combine with the Signal I/O system for more advanced entity communication.