mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-11 15:51:36 +00:00
6d5ffa9f8e
There's still some cleanup to do, but everything seems to be working nicely: `make -j` works, `make distcheck` passes. There is probably plenty of bitrot in the package directories (RPM, debian), though. The vc project files have been removed since those versions are way out of date and quakeforge is pretty much dependent on gcc now anyway. Most of the old Makefile.am files are now Makemodule.am. This should allow for new Makefile.am files that allow local building (to be added on an as-needed bases). The current remaining Makefile.am files are for standalone sub-projects.a The installable bins are currently built in the top-level build directory. This may change if the clutter gets to be too much. While this does make a noticeable difference in build times, the main reason for the switch was to take care of the growing dependency issues: now it's possible to build tools for code generation (eg, using qfcc and ruamoko programs for code-gen).
634 lines
17 KiB
C
634 lines
17 KiB
C
/*
|
|
cl_ents.c
|
|
|
|
entity parsing and management
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
|
|
#include "QF/cvar.h"
|
|
#include "QF/locs.h"
|
|
#include "QF/msg.h"
|
|
#include "QF/render.h"
|
|
#include "QF/skin.h"
|
|
#include "QF/sys.h"
|
|
|
|
#include "compat.h"
|
|
#include "clview.h"
|
|
#include "d_iface.h"
|
|
|
|
#include "qw/bothdefs.h"
|
|
#include "qw/msg_ucmd.h"
|
|
#include "qw/pmove.h"
|
|
|
|
#include "qw/include/chase.h"
|
|
#include "qw/include/cl_cam.h"
|
|
#include "qw/include/cl_ents.h"
|
|
#include "qw/include/cl_main.h"
|
|
#include "qw/include/cl_parse.h"
|
|
#include "qw/include/cl_pred.h"
|
|
#include "qw/include/cl_tent.h"
|
|
#include "qw/include/host.h"
|
|
|
|
entity_t cl_player_ents[MAX_CLIENTS];
|
|
entity_t cl_flag_ents[MAX_CLIENTS];
|
|
entity_t cl_entities[512]; // FIXME: magic number
|
|
byte cl_entity_valid[2][512];
|
|
|
|
void
|
|
CL_ClearEnts (void)
|
|
{
|
|
size_t i;
|
|
|
|
i = qw_entstates.num_frames * qw_entstates.num_entities;
|
|
memset (qw_entstates.frame[0], 0, i * sizeof (entity_state_t));
|
|
memset (cl_entity_valid, 0, sizeof (cl_entity_valid));
|
|
for (i = 0; i < sizeof (cl_entities) / sizeof (cl_entities[0]); i++)
|
|
CL_Init_Entity (&cl_entities[i]);
|
|
for (i = 0; i < sizeof (cl_flag_ents) / sizeof (cl_flag_ents[0]); i++)
|
|
CL_Init_Entity (&cl_flag_ents[i]);
|
|
for (i = 0; i < sizeof (cl_player_ents) / sizeof (cl_player_ents[0]); i++)
|
|
CL_Init_Entity (&cl_player_ents[i]);
|
|
}
|
|
|
|
static void
|
|
CL_NewDlight (int key, vec3_t org, int effects, byte glow_size,
|
|
byte glow_color)
|
|
{
|
|
float radius;
|
|
dlight_t *dl;
|
|
static quat_t normal = {0.4, 0.2, 0.05, 0.7};
|
|
static quat_t red = {0.5, 0.05, 0.05, 0.7};
|
|
static quat_t blue = {0.05, 0.05, 0.5, 0.7};
|
|
static quat_t purple = {0.5, 0.05, 0.5, 0.7};
|
|
|
|
effects &= EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT;
|
|
if (!effects) {
|
|
if (!glow_size)
|
|
return;
|
|
}
|
|
|
|
dl = r_funcs->R_AllocDlight (key);
|
|
if (!dl)
|
|
return;
|
|
VectorCopy (org, dl->origin);
|
|
|
|
if (effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT)) {
|
|
radius = 200 + (rand () & 31);
|
|
if (effects & EF_BRIGHTLIGHT) {
|
|
radius += 200;
|
|
dl->origin[2] += 16;
|
|
}
|
|
if (effects & EF_DIMLIGHT)
|
|
if (effects & ~EF_DIMLIGHT)
|
|
radius -= 100;
|
|
dl->radius = radius;
|
|
dl->die = cl.time + 0.1;
|
|
|
|
switch (effects & (EF_RED | EF_BLUE)) {
|
|
case EF_RED | EF_BLUE:
|
|
QuatCopy (purple, dl->color);
|
|
break;
|
|
case EF_RED:
|
|
QuatCopy (red, dl->color);
|
|
break;
|
|
case EF_BLUE:
|
|
QuatCopy (blue, dl->color);
|
|
break;
|
|
default:
|
|
QuatCopy (normal, dl->color);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (glow_size) {
|
|
dl->radius += glow_size < 128 ? glow_size * 8.0 :
|
|
(glow_size - 256) * 8.0;
|
|
dl->die = cl.time + 0.1;
|
|
if (glow_color) {
|
|
if (glow_color == 255) {
|
|
dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
|
|
} else {
|
|
byte *tempcolor;
|
|
|
|
tempcolor = (byte *) &d_8to24table[glow_color];
|
|
VectorScale (tempcolor, 1 / 255.0, dl->color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hack hack hack
|
|
static inline int
|
|
is_dead_body (entity_state_t *s1)
|
|
{
|
|
int i = s1->frame;
|
|
|
|
if (s1->modelindex == cl_playerindex
|
|
&& (i == 49 || i == 60 || i == 69 || i == 84 || i == 93 || i == 102))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
// Hack hack hack
|
|
static inline int
|
|
is_gib (entity_state_t *s1)
|
|
{
|
|
if (s1->modelindex == cl_h_playerindex || s1->modelindex == cl_gib1index
|
|
|| s1->modelindex == cl_gib2index || s1->modelindex == cl_gib3index)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force)
|
|
{
|
|
vec3_t ang;
|
|
vec_t *forward, *left, *up;
|
|
|
|
if (VectorIsZero (angles)) {
|
|
VectorSet (1, 0, 0, ent->transform + 0);
|
|
VectorSet (0, 1, 0, ent->transform + 4);
|
|
VectorSet (0, 0, 1, ent->transform + 8);
|
|
} else if (force || !VectorCompare (angles, ent->angles)) {
|
|
forward = ent->transform + 0;
|
|
left = ent->transform + 4;
|
|
up = ent->transform + 8;
|
|
VectorCopy (angles, ang);
|
|
if (ent->model && ent->model->type == mod_alias) {
|
|
// stupid quake bug
|
|
// why, oh, why, do alias models pitch in the opposite direction
|
|
// to everything else?
|
|
ang[PITCH] = -ang[PITCH];
|
|
}
|
|
AngleVectors (ang, forward, left, up);
|
|
VectorNegate (left, left); // AngleVectors is right-handed
|
|
}
|
|
VectorCopy (angles, ent->angles);
|
|
ent->transform[3] = 0;
|
|
ent->transform[7] = 0;
|
|
ent->transform[11] = 0;
|
|
VectorCopy (ent->origin, ent->transform + 12);
|
|
ent->transform[15] = 1;
|
|
}
|
|
|
|
static void
|
|
CL_ModelEffects (entity_t *ent, int num, int glow_color)
|
|
{
|
|
dlight_t *dl;
|
|
model_t *model = ent->model;
|
|
|
|
// add automatic particle trails
|
|
if (model->flags & EF_ROCKET) {
|
|
dl = r_funcs->R_AllocDlight (num);
|
|
if (dl) {
|
|
VectorCopy (ent->origin, dl->origin);
|
|
dl->radius = 200.0;
|
|
dl->die = cl.time + 0.1;
|
|
//FIXME VectorCopy (r_firecolor->vec, dl->color);
|
|
VectorSet (0.9, 0.7, 0.0, dl->color);
|
|
dl->color[3] = 0.7;
|
|
}
|
|
r_funcs->particles->R_RocketTrail (ent);
|
|
} else if (model->flags & EF_GRENADE)
|
|
r_funcs->particles->R_GrenadeTrail (ent);
|
|
else if (model->flags & EF_GIB)
|
|
r_funcs->particles->R_BloodTrail (ent);
|
|
else if (model->flags & EF_ZOMGIB)
|
|
r_funcs->particles->R_SlightBloodTrail (ent);
|
|
else if (model->flags & EF_TRACER)
|
|
r_funcs->particles->R_WizTrail (ent);
|
|
else if (model->flags & EF_TRACER2)
|
|
r_funcs->particles->R_FlameTrail (ent);
|
|
else if (model->flags & EF_TRACER3)
|
|
r_funcs->particles->R_VoorTrail (ent);
|
|
else if (model->flags & EF_GLOWTRAIL)
|
|
if (r_funcs->particles->R_GlowTrail)
|
|
r_funcs->particles->R_GlowTrail (ent, glow_color);
|
|
}
|
|
|
|
static void
|
|
set_entity_model (entity_t *ent, int modelindex)
|
|
{
|
|
ent->model = cl.model_precache[modelindex];
|
|
// automatic animation (torches, etc) can be either all together
|
|
// or randomized
|
|
if (ent->model) {
|
|
if (ent->model->synctype == ST_RAND)
|
|
ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff;
|
|
else
|
|
ent->syncbase = 0.0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
CL_LinkPacketEntities (void)
|
|
{
|
|
int i, j, forcelink;
|
|
float frac, f;
|
|
entity_t *ent;
|
|
entity_state_t *new, *old;
|
|
vec3_t delta;
|
|
|
|
frac = 1;
|
|
for (i = 0; i < 512; i++) {
|
|
new = &qw_entstates.frame[cl.link_sequence & UPDATE_MASK][i];
|
|
old = &qw_entstates.frame[cl.prev_sequence & UPDATE_MASK][i];
|
|
ent = &cl_entities[i];
|
|
forcelink = cl_entity_valid[0][i] != cl_entity_valid[1][i];
|
|
cl_entity_valid[1][i] = cl_entity_valid[0][i];
|
|
// if the object wasn't included in the last packet, remove it
|
|
if (!cl_entity_valid[0][i]) {
|
|
ent->model = NULL;
|
|
ent->pose1 = ent->pose2 = -1;
|
|
if (ent->efrag)
|
|
r_funcs->R_RemoveEfrags (ent); // just became empty
|
|
continue;
|
|
}
|
|
|
|
// spawn light flashes, even ones coming from invisible objects
|
|
CL_NewDlight (i, new->origin, new->effects, new->glow_size,
|
|
new->glow_color);
|
|
|
|
// if set to invisible, skip
|
|
if (!new->modelindex
|
|
|| (cl_deadbodyfilter->int_val && is_dead_body (new))
|
|
|| (cl_gibfilter->int_val && is_gib (new))) {
|
|
if (ent->efrag)
|
|
r_funcs->R_RemoveEfrags (ent);
|
|
continue;
|
|
}
|
|
|
|
if (forcelink)
|
|
*old = *new;
|
|
|
|
if (forcelink || new->modelindex != old->modelindex) {
|
|
old->modelindex = new->modelindex;
|
|
set_entity_model (ent, new->modelindex);
|
|
}
|
|
ent->frame = new->frame;
|
|
if (forcelink || new->colormap != old->colormap
|
|
|| new->skinnum != old->skinnum) {
|
|
old->skinnum = new->skinnum;
|
|
ent->skinnum = new->skinnum;
|
|
old->colormap = new->colormap;
|
|
if (new->colormap && (new->colormap <= MAX_CLIENTS)
|
|
&& cl.players[new->colormap - 1].name
|
|
&& cl.players[new->colormap - 1].name->value[0]
|
|
&& new->modelindex == cl_playerindex) {
|
|
player_info_t *player = &cl.players[new->colormap - 1];
|
|
ent->skin = mod_funcs->Skin_SetSkin (ent->skin, new->colormap,
|
|
player->skinname->value);
|
|
ent->skin = mod_funcs->Skin_SetColormap (ent->skin,
|
|
new->colormap);
|
|
} else {
|
|
ent->skin = mod_funcs->Skin_SetColormap (ent->skin, 0);
|
|
}
|
|
}
|
|
ent->scale = new->scale / 16.0;
|
|
|
|
VectorCopy (ent_colormod[new->colormod], ent->colormod);
|
|
ent->colormod[3] = new->alpha / 255.0;
|
|
|
|
ent->min_light = 0;
|
|
ent->fullbright = 0;
|
|
if (new->modelindex == cl_playerindex) {
|
|
ent->min_light = min (cl.fbskins, cl_fb_players->value);
|
|
if (ent->min_light >= 1.0)
|
|
ent->fullbright = 1;
|
|
}
|
|
|
|
if (forcelink) {
|
|
ent->pose1 = ent->pose2 = -1;
|
|
VectorCopy (new->origin, ent->origin);
|
|
if (!(ent->model->flags & EF_ROTATE))
|
|
CL_TransformEntity (ent, new->angles, true);
|
|
if (i != cl.viewentity || chase_active->int_val) {
|
|
if (ent->efrag)
|
|
r_funcs->R_RemoveEfrags (ent);
|
|
r_funcs->R_AddEfrags (ent);
|
|
}
|
|
VectorCopy (ent->origin, ent->old_origin);
|
|
} else {
|
|
f = frac;
|
|
VectorCopy (ent->origin, ent->old_origin);
|
|
VectorSubtract (new->origin, old->origin, delta);
|
|
// If the delta is large, assume a teleport and don't lerp
|
|
if (fabs (delta[0]) > 100 || fabs (delta[1] > 100)
|
|
|| fabs (delta[2]) > 100) {
|
|
// assume a teleportation, not a motion
|
|
VectorCopy (new->origin, ent->origin);
|
|
if (!(ent->model->flags & EF_ROTATE))
|
|
CL_TransformEntity (ent, new->angles, true);
|
|
ent->pose1 = ent->pose2 = -1;
|
|
} else {
|
|
vec3_t angles, d;
|
|
// interpolate the origin and angles
|
|
VectorMultAdd (old->origin, f, delta, ent->origin);
|
|
if (!(ent->model->flags & EF_ROTATE)) {
|
|
VectorSubtract (new->angles, old->angles, d);
|
|
for (j = 0; j < 3; j++) {
|
|
if (d[j] > 180)
|
|
d[j] -= 360;
|
|
else if (d[j] < -180)
|
|
d[j] += 360;
|
|
}
|
|
VectorMultAdd (old->angles, f, d, angles);
|
|
CL_TransformEntity (ent, angles, false);
|
|
}
|
|
}
|
|
if (i != cl.viewentity || chase_active->int_val) {
|
|
if (ent->efrag) {
|
|
if (!VectorCompare (ent->origin, ent->old_origin)) {
|
|
r_funcs->R_RemoveEfrags (ent);
|
|
r_funcs->R_AddEfrags (ent);
|
|
}
|
|
} else {
|
|
r_funcs->R_AddEfrags (ent);
|
|
}
|
|
}
|
|
}
|
|
if (!ent->efrag)
|
|
r_funcs->R_AddEfrags (ent);
|
|
|
|
// rotate binary objects locally
|
|
if (ent->model->flags & EF_ROTATE) {
|
|
vec3_t angles;
|
|
angles[PITCH] = 0;
|
|
angles[YAW] = anglemod (100 * cl.time);
|
|
angles[ROLL] = 0;
|
|
CL_TransformEntity (ent, angles, false);
|
|
}
|
|
//CL_EntityEffects (i, ent, new);
|
|
//CL_NewDlight (i, ent->origin, new->effects, 0, 0);
|
|
if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256))
|
|
VectorCopy (ent->origin, old->origin);
|
|
if (ent->model->flags & ~EF_ROTATE)
|
|
CL_ModelEffects (ent, -new->number, new->glow_color);
|
|
}
|
|
}
|
|
|
|
/*
|
|
CL_AddFlagModels
|
|
|
|
Called when the CTF flags are set. Flags are effectively temp entities.
|
|
|
|
NOTE: this must be called /after/ the entity has been transformed as it
|
|
uses the entity's transform matrix to get the frame vectors
|
|
*/
|
|
static void
|
|
CL_AddFlagModels (entity_t *ent, int team, int key)
|
|
{
|
|
static float flag_offsets[] = {
|
|
16.0, 22.0, 26.0, 25.0, 24.0, 18.0, // 29-34 axpain
|
|
16.0, 24.0, 24.0, 22.0, 18.0, 16.0, // 35-40 pain
|
|
};
|
|
float f;
|
|
entity_t *fent;
|
|
vec_t *v_forward, *v_left;
|
|
vec3_t ang;
|
|
|
|
if (cl_flagindex == -1)
|
|
return;
|
|
|
|
f = 14.0;
|
|
if (ent->frame >= 29 && ent->frame <= 40) {
|
|
f = flag_offsets[ent->frame - 29];
|
|
} else if (ent->frame >= 103 && ent->frame <= 118) {
|
|
if (ent->frame <= 106) // 103-104 nailattack
|
|
f = 20.0; // 105-106 light
|
|
else // 107-112 rocketattack
|
|
f = 21.0; // 112-118 shotattack
|
|
}
|
|
|
|
fent = &cl_flag_ents[key];
|
|
fent->model = cl.model_precache[cl_flagindex];
|
|
fent->skinnum = team;
|
|
|
|
v_forward = ent->transform + 0;
|
|
v_left = ent->transform + 4;
|
|
|
|
VectorMultAdd (ent->origin, -f, v_forward, fent->origin);
|
|
VectorMultAdd (fent->origin, -22, v_left, fent->origin);
|
|
fent->origin[2] -= 16.0;
|
|
|
|
VectorCopy (ent->angles, ang);
|
|
ang[2] -= 45.0;
|
|
CL_TransformEntity (fent, ang, false);
|
|
|
|
r_funcs->R_EnqueueEntity (fent);//FIXME should use efrag (needs smarter
|
|
// handling //in the player code)
|
|
}
|
|
|
|
/*
|
|
CL_LinkPlayers
|
|
|
|
Create visible entities in the correct position
|
|
for all current players
|
|
*/
|
|
static void
|
|
CL_LinkPlayers (void)
|
|
{
|
|
double playertime;
|
|
int msec, oldphysent, i, j;
|
|
entity_t *ent;
|
|
frame_t *frame;
|
|
player_info_t *info;
|
|
player_state_t exact;
|
|
player_state_t *state;
|
|
qboolean clientplayer;
|
|
vec3_t org, ang = {0, 0, 0};
|
|
|
|
playertime = realtime - cls.latency + 0.02;
|
|
if (playertime > realtime)
|
|
playertime = realtime;
|
|
|
|
frame = &cl.frames[cl.parsecount & UPDATE_MASK];
|
|
|
|
for (j = 0, info = cl.players, state = frame->playerstate; j < MAX_CLIENTS;
|
|
j++, info++, state++) {
|
|
ent = &cl_player_ents[j];
|
|
if (ent->efrag)
|
|
r_funcs->R_RemoveEfrags (ent);
|
|
if (state->messagenum != cl.parsecount)
|
|
continue; // not present this frame
|
|
|
|
if (!info->name || !info->name->value[0])
|
|
continue;
|
|
|
|
// spawn light flashes, even ones coming from invisible objects
|
|
if (j == cl.playernum) {
|
|
VectorCopy (cl.simorg, org);
|
|
r_data->player_entity = &cl_player_ents[j];
|
|
clientplayer = true;
|
|
} else {
|
|
VectorCopy (state->pls.origin, org);
|
|
clientplayer = false;
|
|
}
|
|
if (info->chat && info->chat->value[0] != '0') {
|
|
dlight_t *dl = r_funcs->R_AllocDlight (j + 1);
|
|
VectorCopy (org, dl->origin);
|
|
dl->radius = 100;
|
|
dl->die = cl.time + 0.1;
|
|
QuatSet (0.0, 1.0, 0.0, 1.0, dl->color);
|
|
} else {
|
|
CL_NewDlight (j + 1, org, state->pls.effects, state->pls.glow_size,
|
|
state->pls.glow_color);
|
|
}
|
|
|
|
// Draw player?
|
|
if (!Cam_DrawPlayer (j))
|
|
continue;
|
|
|
|
if (!state->pls.modelindex)
|
|
continue;
|
|
|
|
// Hack hack hack
|
|
if (cl_deadbodyfilter->int_val
|
|
&& state->pls.modelindex == cl_playerindex
|
|
&& ((i = state->pls.frame) == 49 || i == 60 || i == 69 || i == 84
|
|
|| i == 93 || i == 102))
|
|
continue;
|
|
|
|
// predict only half the move to minimize overruns
|
|
msec = 500 * (playertime - state->state_time);
|
|
if (msec <= 0 || (!cl_predict_players->int_val) || cls.demoplayback2) {
|
|
VectorCopy (state->pls.origin, ent->origin);
|
|
} else { // predict players movement
|
|
state->pls.cmd.msec = msec = min (msec, 255);
|
|
|
|
oldphysent = pmove.numphysent;
|
|
CL_SetSolidPlayers (j);
|
|
CL_PredictUsercmd (state, &exact, &state->pls.cmd, clientplayer);
|
|
pmove.numphysent = oldphysent;
|
|
VectorCopy (exact.pls.origin, ent->origin);
|
|
}
|
|
|
|
// angles
|
|
if (j == cl.playernum)
|
|
{
|
|
ang[PITCH] = -cl.viewangles[PITCH] / 3.0;
|
|
ang[YAW] = cl.viewangles[YAW];
|
|
} else {
|
|
ang[PITCH] = -state->viewangles[PITCH] / 3.0;
|
|
ang[YAW] = state->viewangles[YAW];
|
|
}
|
|
ang[ROLL] = V_CalcRoll (ang, state->pls.velocity) * 4.0;
|
|
|
|
ent->model = cl.model_precache[state->pls.modelindex];
|
|
ent->frame = state->pls.frame;
|
|
ent->skinnum = state->pls.skinnum;
|
|
|
|
CL_TransformEntity (ent, ang, false);
|
|
|
|
ent->min_light = 0;
|
|
ent->fullbright = 0;
|
|
|
|
if (state->pls.modelindex == cl_playerindex) { //XXX
|
|
// use custom skin
|
|
ent->skin = info->skin;
|
|
|
|
ent->min_light = min (cl.fbskins, cl_fb_players->value);
|
|
|
|
if (ent->min_light >= 1.0)
|
|
ent->fullbright = 1;
|
|
} else {
|
|
// FIXME no team colors on nonstandard player models
|
|
ent->skin = 0;
|
|
}
|
|
|
|
// stuff entity in map
|
|
r_funcs->R_AddEfrags (ent);
|
|
|
|
if (state->pls.effects & EF_FLAG1)
|
|
CL_AddFlagModels (ent, 0, j);
|
|
else if (state->pls.effects & EF_FLAG2)
|
|
CL_AddFlagModels (ent, 1, j);
|
|
}
|
|
}
|
|
|
|
/*
|
|
CL_EmitEntities
|
|
|
|
Builds the visedicts array for cl.time
|
|
|
|
Made up of: clients, packet_entities, nails, and tents
|
|
*/
|
|
void
|
|
CL_EmitEntities (void)
|
|
{
|
|
if (cls.state != ca_active)
|
|
return;
|
|
if (!cl.validsequence)
|
|
return;
|
|
|
|
CL_LinkPlayers ();
|
|
CL_LinkPacketEntities ();
|
|
CL_UpdateTEnts ();
|
|
if (cl_draw_locs->int_val) {
|
|
//FIXME custom ent rendering code would be nice
|
|
dlight_t *dl;
|
|
location_t *nearloc;
|
|
vec3_t trueloc;
|
|
int i;
|
|
|
|
nearloc = locs_find (cl.simorg);
|
|
if (nearloc) {
|
|
dl = r_funcs->R_AllocDlight (4096);
|
|
if (dl) {
|
|
VectorCopy (nearloc->loc, dl->origin);
|
|
dl->radius = 200;
|
|
dl->die = r_data->realtime + 0.1;
|
|
dl->color[0] = 0;
|
|
dl->color[1] = 1;
|
|
dl->color[2] = 0;
|
|
dl->color[3] = 0.7;
|
|
}
|
|
VectorCopy (nearloc->loc, trueloc);
|
|
r_funcs->particles->R_Particle_New (pt_smokecloud, part_tex_smoke,
|
|
trueloc, 2.0,
|
|
vec3_origin, r_data->realtime + 9.0, 254,
|
|
0.25 + qfrandom (0.125), 0.0);
|
|
for (i = 0; i < 15; i++)
|
|
r_funcs->particles->R_Particle_NewRandom (pt_fallfade,
|
|
part_tex_dot, trueloc, 12,
|
|
0.7, 96, r_data->realtime + 5.0,
|
|
104 + (rand () & 7), 1.0, 0.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CL_Ents_Init (void)
|
|
{
|
|
r_data->view_model = &cl.viewent;
|
|
}
|