/** * @brief Creates an effect trail for the specified entity. */ static void G_trigger_push_Effect(g_entity_t *self) { g_entity_t *ent = G_AllocEntity(); VectorAdd(self->mins, self->maxs, ent->s.origin); VectorScale(ent->s.origin, 0.5, ent->s.origin); ent->locals.move_type = MOVE_TYPE_NONE; ent->s.trail = TRAIL_TELEPORTER; gi.LinkEntity(ent); }
/** * @brief Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void G_SpawnEntities(const char *name, const char *entities) { gi.FreeTag(MEM_TAG_GAME_LEVEL); memset(&g_level, 0, sizeof(g_level)); g_strlcpy(g_level.name, name, sizeof(g_level.name)); // see if we have bots to keep if (aix) { g_game.ai_fill_slots = 0; g_game.ai_left_to_spawn = 0; if (g_ai_max_clients->integer) { if (g_ai_max_clients->integer == -1) { g_game.ai_fill_slots = sv_max_clients->integer; } else { g_game.ai_fill_slots = Clamp(g_ai_max_clients->integer, 0, sv_max_clients->integer); } g_game.ai_left_to_spawn = g_game.ai_fill_slots; g_ai_max_clients->modified = false; } else { for (int32_t i = 0; i < sv_max_clients->integer; i++) { if (g_game.entities[i + 1].client && g_game.entities[i + 1].client->ai) { g_game.ai_left_to_spawn++; } } } } memset(g_game.entities, 0, g_max_entities->value * sizeof(g_entity_t)); memset(g_game.clients, 0, sv_max_clients->value * sizeof(g_client_t)); for (int32_t i = 0; i < sv_max_clients->integer; i++) { g_game.entities[i + 1].client = g_game.clients + i; } ge.num_entities = sv_max_clients->integer + 1; g_entity_t *ent = NULL; gchar **inhibit = g_strsplit(g_inhibit->string, " ", -1); int32_t inhibited = 0; parser_t parser; char tok[MAX_QPATH]; Parse_Init(&parser, entities, PARSER_NO_COMMENTS); // parse the entity definition string while (true) { if (!Parse_Token(&parser, PARSE_DEFAULT, tok, sizeof(tok))) { break; } if (tok[0] != '{') { gi.Error("Found \"%s\" when expecting \"{\"", tok); } if (ent == NULL) { ent = g_game.entities; } else { ent = G_AllocEntity(); } G_ParseEntity(&parser, ent); if (ent != g_game.entities) { // enforce entity inhibiting for (size_t i = 0; i < g_strv_length(inhibit); i++) { if (g_strcmp0(ent->class_name, inhibit[i]) == 0) { G_FreeEntity(ent); inhibited++; continue; } } // handle legacy spawn flags if (ent->locals.spawn_flags & SF_NOT_DEATHMATCH) { G_FreeEntity(ent); inhibited++; continue; } // strip away unsupported flags ent->locals.spawn_flags &= ~(SF_NOT_EASY | SF_NOT_MEDIUM | SF_NOT_HARD | SF_NOT_COOP); } if (!G_SpawnEntity(ent)) { G_FreeEntity(ent); inhibited++; } } g_strfreev(inhibit); gi.Debug("%i entities inhibited\n", inhibited); G_InitMedia(); G_InitEntityTeams(); G_CheckHook(); G_CheckTechs(); G_ResetTeams(); G_InitSpawnPoints(); G_ResetSpawnPoints(); G_ResetVote(); G_ResetItems(); }
/* * @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; } } } } }