/* * @brief Searches all active entities for the next targeted one. * * Searches beginning at the entity after from, or the beginning if NULL * NULL will be returned if the end of the list is reached. */ g_entity_t *G_PickTarget(char *target_name) { g_entity_t *choice[MAX_TARGETS]; size_t num_choices = 0; if (!target_name) { gi.Debug("NULL target_name\n"); return NULL; } g_entity_t *ent = NULL; while (true) { ent = G_Find(ent, LOFS(target_name), target_name); if (!ent) break; choice[num_choices++] = ent; if (num_choices == MAX_TARGETS) break; } if (!num_choices) { gi.Debug("Target %s not found\n", target_name); return NULL; } return choice[Random() % num_choices]; }
F_STRING, // string on disk, pointer in memory, TAG_LEVEL F_VECTOR, F_ANGLE } g_field_type_t; typedef struct g_field_s { char *name; ptrdiff_t ofs; g_field_type_t type; int32_t flags; } g_field_t; static const g_field_t fields[] = { { "classname", EOFS(class_name), F_STRING, 0 }, { "model", EOFS(model), F_STRING, 0 }, { "spawnflags", LOFS(spawn_flags), F_INT, 0 }, { "speed", LOFS(speed), F_FLOAT, 0 }, { "accel", LOFS(accel), F_FLOAT, 0 }, { "decel", LOFS(decel), F_FLOAT, 0 }, { "target", LOFS(target), F_STRING, 0 }, { "targetname", LOFS(target_name), F_STRING, 0 }, { "pathtarget", LOFS(path_target), F_STRING, 0 }, { "killtarget", LOFS(kill_target), F_STRING, 0 }, { "message", LOFS(message), F_STRING, 0 }, { "team", LOFS(team), F_STRING, 0 }, { "command", LOFS(command), F_STRING, 0 }, { "script", LOFS(script), F_STRING, 0 }, { "wait", LOFS(wait), F_FLOAT, 0 }, { "delay", LOFS(delay), F_FLOAT, 0 }, { "random", LOFS(random), F_FLOAT, 0 }, { "style", LOFS(area_portal), F_INT, 0 }, // HACK, this was always overloaded
/* * @brief Search for all entities that the specified entity targets, and call their * use functions. Set their activator to our activator. Print our message, * if set, to the activator. */ void G_UseTargets(g_entity_t *ent, g_entity_t *activator) { g_entity_t *t; // check for a delay if (ent->locals.delay) { // create a temp object to fire at a later time t = G_AllocEntity(__func__); t->locals.next_think = g_level.time + ent->locals.delay * 1000; t->locals.Think = G_UseTargets_Delay; t->locals.activator = activator; if (!activator) gi.Debug("No activator for %s\n", etos(ent)); t->locals.message = ent->locals.message; t->locals.target = ent->locals.target; t->locals.kill_target = ent->locals.kill_target; return; } // print the message if ((ent->locals.message) && activator->client) { gi.WriteByte(SV_CMD_CENTER_PRINT); gi.WriteString(ent->locals.message); gi.Unicast(activator, true); if (ent->locals.noise_index) gi.Sound(activator, ent->locals.noise_index, ATTEN_NORM); else gi.Sound(activator, gi.SoundIndex("misc/chat"), ATTEN_NORM); } // kill kill_targets if (ent->locals.kill_target) { t = NULL; while ((t = G_Find(t, LOFS(target_name), ent->locals.kill_target))) { G_FreeEntity(t); if (!ent->in_use) { gi.Debug("%s was removed while using kill_targets\n", etos(ent)); return; } } } // doors fire area portals in a specific way const _Bool is_door = g_str_has_prefix(ent->class_name, "func_door"); // fire targets if (ent->locals.target) { t = NULL; while ((t = G_Find(t, LOFS(target_name), ent->locals.target))) { if (is_door && !g_strcmp0(t->class_name, "func_areaportal")) { continue; } if (t == ent) { gi.Debug("%s tried to use itself\n", etos(ent)); continue; } if (t->locals.Use) { t->locals.Use(t, ent, activator); if (!ent->in_use) { // see if our target freed us gi.Debug("%s was removed while using targets\n", etos(ent)); break; } } } } }