[client] Merge nq and qw temp entity handling

This finally gets cl_tent merged away.
This commit is contained in:
Bill Currie 2021-03-10 18:00:16 +09:00
parent fbc1bd9f6e
commit 098ceed5ff
22 changed files with 482 additions and 957 deletions

View file

@ -67,4 +67,7 @@ extern entstates_t qw_entstates;
extern vec3_t ent_colormod[256];
struct entity_s;
void CL_TransformEntity (struct entity_s *ent, const vec3_t angles);
#endif//__client_entities_h

View file

@ -0,0 +1,119 @@
/*
temp_entities.h
Temporary entity management
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2021/3/10
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
*/
#ifndef __client_temp_entities_h
#define __client_temp_entities_h
#include "QF/simd/vec4f.h"
typedef enum TE_Effect {
TE_NoEffect, // for invalid nq/qw -> qf mapping
TE_Beam, // grappling hook beam
TE_Blood, // bullet hitting body
TE_Explosion, // rocket explosion
TE_Explosion2, // color mapped explosion
TE_Explosion3, // Nehahra colored light explosion
TE_Gunshot1, // NQ gunshot (20 particles)
TE_Gunshot2, // QW gunshot (has particle count)
TE_KnightSpike, // spike hitting wall
TE_LavaSplash,
TE_Lightning1, // lightning bolts
TE_Lightning2, // lightning bolts
TE_Lightning3, // lightning bolts
TE_Lightning4, // Nehahra lightning
TE_LightningBlood, // lightning hitting body
TE_Spike, // spike hitting wall
TE_SuperSpike, // super spike hitting wall
TE_TarExplosion, // tarbaby explosion
TE_Teleport,
TE_WizSpike, // spike hitting wall
} TE_Effect;
typedef enum TE_nqEffect {
TE_nqSpike,
TE_nqSuperSpike,
TE_nqGunshot,
TE_nqExplosion,
TE_nqTarExplosion,
TE_nqLightning1,
TE_nqLightning2,
TE_nqWizSpike,
TE_nqKnightSpike,
TE_nqLightning3,
TE_nqLavaSplash,
TE_nqTeleport,
TE_nqExplosion2,
TE_nqBeam,
TE_nqExplosion3 = 16,
TE_nqLightning4,
} TE_nqEffect;
typedef enum TE_qwEffect {
TE_qwSpike,
TE_qwSuperSpike,
TE_qwGunshot,
TE_qwExplosion,
TE_qwTarExplosion,
TE_qwLightning1,
TE_qwLightning2,
TE_qwWizSpike,
TE_qwKnightSpike,
TE_qwLightning3,
TE_qwLavaSplash,
TE_qwTeleport,
TE_qwBlood,
TE_qwLightningBlood,
TE_qwExplosion2 = 16,
TE_qwBeam,
} TE_qwEffect;
//FIXME find a better way to get this info from the parser
typedef struct TEntContext_s {
vec4f_t simorg;
struct model_s *worldModel;
int playerEntity;
} TEntContext_t;
struct msg_s;
struct entity_s;
void CL_TEnts_Init (void);
void CL_Init_Entity (struct entity_s *ent);
void CL_ClearTEnts (void);
void CL_UpdateTEnts (double time, TEntContext_t *ctx);
void CL_ParseTEnt_nq (struct msg_s *net_message, double time,
TEntContext_t *ctx);
void CL_ParseTEnt_qw (struct msg_s *net_message, double time,
TEntContext_t *ctx);
void CL_ParseParticleEffect (struct msg_s *net_message);
void CL_ClearProjectiles (void);
void CL_ParseProjectiles (struct msg_s *net_message, qboolean nail2,
TEntContext_t *ctx);
#endif//__client_temp_entities_h

View file

@ -3,4 +3,6 @@ noinst_LTLIBRARIES += libs/client/libQFclient.la
libs_client_libQFclient_la_LDFLAGS= @STATIC@
libs_client_libQFclient_la_LIBADD= libs/gamecode/libQFgamecode.la libs/util/libQFutil.la
libs_client_libQFclient_la_SOURCES= \
libs/client/cl_entities.c
libs/client/cl_temp_entities.c \
libs/client/cl_entities.c \
$e

View file

@ -31,6 +31,10 @@
# include "config.h"
#endif
#include "QF/entity.h"
#include "QF/render.h" //FIXME for entity_t
#include "QF/simd/vec4f.h"
#include "client/entities.h"
/* QW has a max of 512 entities and wants 64 frames of data per entity, plus
@ -340,3 +344,33 @@ vec3_t ent_colormod[256] = {
{1, 1, 0.666667},
{1, 1, 1}
};
void
CL_TransformEntity (entity_t *ent, const vec3_t angles)
{
union {
quat_t q;
vec4f_t v;
} rotation;
vec4f_t position;
vec4f_t scale;
VectorCopy (ent->origin, position);
position[3] = 1;
VectorSet (ent->scale, ent->scale, ent->scale, scale);
scale[3] = 1;
if (VectorIsZero (angles)) {
QuatSet (0, 0, 0, 1, rotation.q);
} else {
vec3_t ang;
VectorCopy (angles, ang);
if (ent->renderer.model && ent->renderer.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];
}
AngleQuat (ang, rotation.q);
}
Transform_SetLocalTransform (ent->transform, scale, rotation.v, position);
}

View file

@ -1,9 +1,12 @@
/*
cl_tent.c
cl_temp_entities.c
client side temporary entities
Client side temporary entity management
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2021/3/10
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -27,7 +30,6 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
@ -35,23 +37,16 @@
# include <strings.h>
#endif
#include <math.h>
#include <stdlib.h>
#include "QF/console.h"
#include "QF/entity.h"
#include "QF/model.h"
#include "QF/msg.h"
#include "QF/quakefs.h"
#include "QF/render.h"
#include "QF/sound.h"
#include "QF/sys.h"
#include "compat.h"
#include "QF/plugin/vid_render.h" //FIXME
#include "qw/include/cl_ents.h"
#include "qw/include/cl_main.h"
#include "qw/include/cl_parse.h"
#include "qw/include/cl_tent.h"
#include "qw/include/client.h"
#include "client/entities.h"
#include "client/temp_entities.h"
typedef struct tent_s {
struct tent_s *next;
@ -94,28 +89,29 @@ static tent_t *cl_projectiles;
static sfx_t *cl_sfx_wizhit;
static sfx_t *cl_sfx_knighthit;
static sfx_t *cl_sfx_tink1;
static sfx_t *cl_sfx_ric1;
static sfx_t *cl_sfx_ric2;
static sfx_t *cl_sfx_ric3;
static sfx_t *cl_sfx_r_exp3;
static sfx_t *cl_sfx_ric[4];
static model_t *cl_mod_beam;
static model_t *cl_mod_bolt;
static model_t *cl_mod_bolt2;
static model_t *cl_mod_bolt3;
static model_t *cl_spr_explod;
static model_t *cl_spike;
static void
CL_TEnts_Precache (int phase)
{
if (!phase)
if (!phase) {
return;
}
cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
cl_sfx_ric[3] = S_PrecacheSound ("weapons/ric1.wav");
cl_sfx_ric[2] = S_PrecacheSound ("weapons/ric2.wav");
cl_sfx_ric[1] = S_PrecacheSound ("weapons/ric3.wav");
cl_sfx_ric[0] = cl_sfx_ric[1];
cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
cl_mod_bolt = Mod_ForName ("progs/bolt.mdl", true);
@ -123,8 +119,11 @@ CL_TEnts_Precache (int phase)
cl_mod_bolt3 = Mod_ForName ("progs/bolt3.mdl", true);
cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true);
cl_mod_beam = Mod_ForName ("progs/beam.mdl", false);
if (!cl_mod_beam)
cl_spike = Mod_ForName ("progs/spike.mdl", false);
if (!cl_mod_beam) {
cl_mod_beam = cl_mod_bolt;
}
}
void
@ -214,23 +213,23 @@ free_tent_objects (tent_obj_t *tobjs)
void
CL_ClearTEnts (void)
{
tent_t *t;
tent_obj_t *to;
tent_t *tent;
tent_obj_t *tobj;
for (to = cl_beams; to; to = to->next) {
for (t = to->to.beam.tents; t; t = t->next) {
t->ent.visibility.efrag = 0;
for (tobj = cl_beams; tobj; tobj = tobj->next) {
for (tent = tobj->to.beam.tents; tent; tent = tent->next) {
tent->ent.visibility.efrag = 0;
}
free_temp_entities (to->to.beam.tents);
free_temp_entities (tobj->to.beam.tents);
}
free_tent_objects (cl_beams);
cl_beams = 0;
for (to = cl_explosions; to; to = to->next) {
for (t = to->to.ex.tent; t; t = t->next) {
t->ent.visibility.efrag = 0;
for (tobj = cl_explosions; tobj; tobj = tobj->next) {
for (tent = tobj->to.ex.tent; tent; tent = tent->next) {
tent->ent.visibility.efrag = 0;
}
free_temp_entities (to->to.ex.tent);
free_temp_entities (tobj->to.ex.tent);
}
free_tent_objects (cl_explosions);
cl_explosions = 0;
@ -252,7 +251,7 @@ beam_clear (beam_t *b)
}
static inline void
beam_setup (beam_t *b, qboolean transform)
beam_setup (beam_t *b, qboolean transform, double time, TEntContext_t *ctx)
{
tent_t *tent;
float forward, pitch, yaw, d;
@ -287,8 +286,7 @@ beam_setup (beam_t *b, qboolean transform)
ent_count = ceil (d / 30);
d = 0;
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
BEAM_SEED_INTERVAL);
seed = b->seed + ((int) (time * BEAM_SEED_INTERVAL) % BEAM_SEED_INTERVAL);
ang[ROLL] = 0;
while (ent_count--) {
@ -304,15 +302,15 @@ beam_setup (beam_t *b, qboolean transform)
if (transform) {
seed = seed * BEAM_SEED_PRIME;
ang[ROLL] = seed % 360;
CL_TransformEntity (&tent->ent, ang, true);
CL_TransformEntity (&tent->ent, ang);
}
VectorCopy (ang, tent->ent.angles);
r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent);
r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent);
}
}
static void
CL_ParseBeam (model_t *m)
CL_ParseBeam (qmsg_t *net_message, model_t *m, double time, TEntContext_t *ctx)
{
tent_obj_t *to;
beam_t *b;
@ -326,10 +324,12 @@ CL_ParseBeam (model_t *m)
to = 0;
if (ent) {
for (to = cl_beams; to; to = to->next)
if (to->to.beam.entity == ent)
for (to = cl_beams; to; to = to->next) {
if (to->to.beam.entity == ent) {
break;
}
}
}
if (!to) {
to = new_tent_object ();
to->next = cl_beams;
@ -341,93 +341,60 @@ CL_ParseBeam (model_t *m)
beam_clear (b);
b->model = m;
b->endtime = cl.time + 0.2;
b->endtime = time + 0.2;
b->seed = rand ();
VectorCopy (end, b->end);
if (b->entity != cl.viewentity) {
if (b->entity != ctx->playerEntity) {
// this will be done in CL_UpdateBeams
VectorCopy (start, b->start);
beam_setup (b, true);
beam_setup (b, true, time, ctx);
}
}
void
CL_ParseTEnt (void)
static void
parse_tent (qmsg_t *net_message, double time, TEntContext_t *ctx,
TE_Effect type)
{
byte type;
dlight_t *dl;
tent_obj_t *to;
explosion_t *ex;
int colorStart, colorLength;
int cnt = -1;
vec3_t pos;
sfx_t *spike_sound[] = {
cl_sfx_ric3, cl_sfx_ric3, cl_sfx_ric2, cl_sfx_ric1,
};
quat_t color;
vec3_t position;
int count;
const char *name;
type = MSG_ReadByte (net_message);
switch (type) {
case TE_WIZSPIKE: // spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_WizSpikeEffect (pos);
S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
case TE_NoEffect:
// invalid mapping, can't do anything
break;
case TE_KNIGHTSPIKE: // spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_KnightSpikeEffect (pos);
S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
case TE_Beam:
CL_ParseBeam (net_message, cl_mod_beam, time, ctx);
break;
case TE_SPIKE: // spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_SpikeEffect (pos);
{
int i;
sfx_t *sound;
i = (rand () % 20) - 16;
if (i >= 0)
sound = spike_sound[i];
else
sound = cl_sfx_tink1;
S_StartSound (-1, 0, sound, pos, 1, 1);
}
case TE_Blood:
count = MSG_ReadByte (net_message) * 20;
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_BloodPuffEffect (position, count);
break;
case TE_Explosion:
MSG_ReadCoordV (net_message, position);
case TE_SUPERSPIKE: // super spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_SuperSpikeEffect (pos);
{
int i;
sfx_t *sound;
i = (rand () % 20) - 16;
if (i >= 0)
sound = spike_sound[i];
else
sound = cl_sfx_tink1;
S_StartSound (-1, 0, sound, pos, 1, 1);
}
break;
case TE_EXPLOSION: // rocket explosion
// particles
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_ParticleExplosion (pos);
r_funcs->particles->R_ParticleExplosion (position);
// light
dl = r_funcs->R_AllocDlight (0);
if (dl) {
VectorCopy (pos, dl->origin);
VectorCopy (position, dl->origin);
dl->radius = 350;
dl->die = cl.time + 0.5;
dl->die = time + 0.5;
dl->decay = 300;
QuatSet (0.86, 0.31, 0.24, 0.7, dl->color);
//FIXME? nq: QuatSet (1.0, 0.5, 0.25, 0.7, dl->color);
}
// sound
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1);
// sprite
to = new_tent_object ();
@ -436,105 +403,201 @@ CL_ParseTEnt (void)
ex = &to->to.ex;
ex->tent = new_temp_entity ();
VectorCopy (pos, ex->tent->ent.origin);
ex->start = cl.time;
VectorCopy (position, ex->tent->ent.origin);
ex->start = time;
//FIXME need better model management
if (!cl_spr_explod->cache.data)
if (!cl_spr_explod->cache.data) {
cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true);
}
ex->tent->ent.renderer.model = cl_spr_explod;
CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true);
CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles);
break;
case TE_TAREXPLOSION: // tarbaby explosion
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_BlobExplosion (pos);
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
break;
case TE_LIGHTNING1: // lightning bolts
CL_ParseBeam (cl_mod_bolt);
break;
case TE_LIGHTNING2: // lightning bolts
CL_ParseBeam (cl_mod_bolt2);
break;
case TE_LIGHTNING3: // lightning bolts
CL_ParseBeam (cl_mod_bolt3);
break;
// PGM 01/21/97
case TE_BEAM: // grappling hook beam
CL_ParseBeam (cl_mod_beam);
break;
// PGM 01/21/97
case TE_LAVASPLASH:
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_LavaSplash (pos);
break;
case TE_TELEPORT:
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_TeleportSplash (pos);
break;
case TE_EXPLOSION2: // color mapped explosion
MSG_ReadCoordV (net_message, pos);
case TE_Explosion2:
MSG_ReadCoordV (net_message, position);
colorStart = MSG_ReadByte (net_message);
colorLength = MSG_ReadByte (net_message);
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
r_funcs->particles->R_ParticleExplosion2 (pos, colorStart,
S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1);
r_funcs->particles->R_ParticleExplosion2 (position, colorStart,
colorLength);
dl = r_funcs->R_AllocDlight (0);
if (!dl)
break;
VectorCopy (pos, dl->origin);
VectorCopy (position, dl->origin);
dl->radius = 350;
dl->die = cl.time + 0.5;
dl->die = time + 0.5;
dl->decay = 300;
colorStart = (colorStart + (rand () % colorLength)) * 3;
VectorScale (&r_data->vid->palette[colorStart], 1.0 / 255.0,
dl->color);
dl->color[3] = 0.7;
break;
case TE_GUNSHOT: // bullet hitting wall
cnt = MSG_ReadByte (net_message) * 20;
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_GunshotEffect (pos, cnt);
case TE_Explosion3:
MSG_ReadCoordV (net_message, position);
MSG_ReadCoordV (net_message, color); // OUCH!
color[3] = 0.7;
r_funcs->particles->R_ParticleExplosion (position);
S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1);
dl = r_funcs->R_AllocDlight (0);
if (dl) {
VectorCopy (position, dl->origin);
dl->radius = 350;
dl->die = time + 0.5;
dl->decay = 300;
QuatCopy (color, dl->color);
}
break;
case TE_BLOOD: // bullet hitting body
cnt = MSG_ReadByte (net_message) * 20;
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_BloodPuffEffect (pos, cnt);
case TE_Gunshot1:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_GunshotEffect (position, 20);
break;
case TE_LIGHTNINGBLOOD: // lightning hitting body
MSG_ReadCoordV (net_message, pos);
case TE_Gunshot2:
count = MSG_ReadByte (net_message) * 20;
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_GunshotEffect (position, count);
break;
case TE_KnightSpike:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_KnightSpikeEffect (position);
S_StartSound (-1, 0, cl_sfx_knighthit, position, 1, 1);
break;
case TE_LavaSplash:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_LavaSplash (position);
break;
case TE_Lightning1:
CL_ParseBeam (net_message, cl_mod_bolt, time, ctx);
break;
case TE_Lightning2:
CL_ParseBeam (net_message, cl_mod_bolt2, time, ctx);
break;
case TE_Lightning3:
CL_ParseBeam (net_message, cl_mod_bolt3, time, ctx);
break;
case TE_Lightning4:
name = MSG_ReadString (net_message);
CL_ParseBeam (net_message, Mod_ForName (name, true), time, ctx);
break;
case TE_LightningBlood:
MSG_ReadCoordV (net_message, position);
// light
dl = r_funcs->R_AllocDlight (0);
if (dl) {
VectorCopy (pos, dl->origin);
VectorCopy (position, dl->origin);
dl->radius = 150;
dl->die = cl.time + 0.1;
dl->die = time + 0.1;
dl->decay = 200;
QuatSet (0.25, 0.40, 0.65, 1, dl->color);
}
r_funcs->particles->R_LightningBloodEffect (pos);
r_funcs->particles->R_LightningBloodEffect (position);
break;
case TE_Spike:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_SpikeEffect (position);
{
int i;
sfx_t *sound;
default:
Sys_Error ("CL_ParseTEnt: bad type %d", type);
i = (rand () % 20) - 16;
if (i >= 0) {
sound = cl_sfx_ric[i];
} else {
sound = cl_sfx_tink1;
}
S_StartSound (-1, 0, sound, position, 1, 1);
}
break;
case TE_SuperSpike:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_SuperSpikeEffect (position);
{
int i;
sfx_t *sound;
i = (rand () % 20) - 16;
if (i >= 0) {
sound = cl_sfx_ric[i];
} else {
sound = cl_sfx_tink1;
}
S_StartSound (-1, 0, sound, position, 1, 1);
}
break;
case TE_TarExplosion:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_BlobExplosion (position);
S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1);
break;
case TE_Teleport:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_TeleportSplash (position);
break;
case TE_WizSpike:
MSG_ReadCoordV (net_message, position);
r_funcs->particles->R_WizSpikeEffect (position);
S_StartSound (-1, 0, cl_sfx_wizhit, position, 1, 1);
break;
}
}
// the effect type is a byte so a max of 256 values
static const TE_Effect nqEffects[256] = {
[TE_nqSpike] = TE_Spike,
[TE_nqSuperSpike] = TE_SuperSpike,
[TE_nqGunshot] = TE_Gunshot1,
[TE_nqExplosion] = TE_Explosion,
[TE_nqTarExplosion] = TE_TarExplosion,
[TE_nqLightning1] = TE_Lightning1,
[TE_nqLightning2] = TE_Lightning2,
[TE_nqWizSpike] = TE_WizSpike,
[TE_nqKnightSpike] = TE_KnightSpike,
[TE_nqLightning3] = TE_Lightning3,
[TE_nqLavaSplash] = TE_LavaSplash,
[TE_nqTeleport] = TE_Teleport,
[TE_nqExplosion2] = TE_Explosion2,
[TE_nqBeam] = TE_Beam,
[TE_nqExplosion3] = TE_Explosion3,
[TE_nqLightning4] = TE_Lightning4,
};
void
CL_ParseTEnt_nq (qmsg_t *net_message, double time, TEntContext_t *ctx)
{
byte type = MSG_ReadByte (net_message);
parse_tent (net_message, time, ctx, nqEffects[type]);
}
// the effect type is a byte so a max of 256 values
static const TE_Effect qwEffects[256] = {
[TE_qwSpike] = TE_Spike,
[TE_qwSuperSpike] = TE_SuperSpike,
[TE_qwGunshot] = TE_Gunshot2,
[TE_qwExplosion] = TE_Explosion,
[TE_qwTarExplosion] = TE_TarExplosion,
[TE_qwLightning1] = TE_Lightning1,
[TE_qwLightning2] = TE_Lightning2,
[TE_qwWizSpike] = TE_WizSpike,
[TE_qwKnightSpike] = TE_KnightSpike,
[TE_qwLightning3] = TE_Lightning3,
[TE_qwLavaSplash] = TE_LavaSplash,
[TE_qwTeleport] = TE_Teleport,
[TE_qwBlood] = TE_Blood,
[TE_qwLightningBlood] = TE_LightningBlood,
[TE_qwExplosion2] = TE_Explosion2,
[TE_qwBeam] = TE_Beam,
};
void
CL_ParseTEnt_qw (qmsg_t *net_message, double time, TEntContext_t *ctx)
{
byte type = MSG_ReadByte (net_message);
parse_tent (net_message, time, ctx, qwEffects[type]);
}
static void
CL_UpdateBeams (void)
CL_UpdateBeams (double time, TEntContext_t *ctx)
{
tent_obj_t **to;
beam_t *b;
@ -546,7 +609,7 @@ CL_UpdateBeams (void)
b = &(*to)->to.beam;
if (!b->endtime)
continue;
if (!b->model || b->endtime < cl.time) {
if (!b->model || b->endtime < time) {
tent_obj_t *_to;
b->endtime = 0;
beam_clear (b);
@ -559,26 +622,26 @@ CL_UpdateBeams (void)
to = &(*to)->next;
// if coming from the player, update the start position
if (b->entity == cl.viewentity) {
if (b->entity == ctx->playerEntity) {
beam_clear (b);
VectorCopy (cl.simorg, b->start);
beam_setup (b, false);
VectorCopy (ctx->simorg, b->start);
beam_setup (b, false, time, ctx);
}
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
seed = b->seed + ((int) (time * BEAM_SEED_INTERVAL) %
BEAM_SEED_INTERVAL);
// add new entities for the lightning
for (t = b->tents; t; t = t->next) {
seed = seed * BEAM_SEED_PRIME;
t->ent.angles[ROLL] = seed % 360;
CL_TransformEntity (&t->ent, t->ent.angles, true);
CL_TransformEntity (&t->ent, t->ent.angles);
}
}
}
static void
CL_UpdateExplosions (void)
CL_UpdateExplosions (double time, TEntContext_t *ctx)
{
int f;
tent_obj_t **to;
@ -588,7 +651,7 @@ CL_UpdateExplosions (void)
for (to = &cl_explosions; *to; ) {
ex = &(*to)->to.ex;
ent = &ex->tent->ent;
f = 10 * (cl.time - ex->start);
f = 10 * (time - ex->start);
if (f >= ent->renderer.model->numframes) {
tent_obj_t *_to;
r_funcs->R_RemoveEfrags (ent);
@ -604,16 +667,39 @@ CL_UpdateExplosions (void)
ent->animation.frame = f;
if (!ent->visibility.efrag) {
r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent);
r_funcs->R_AddEfrags (&ctx->worldModel->brush, ent);
}
}
}
void
CL_UpdateTEnts (void)
CL_UpdateTEnts (double time, TEntContext_t *ctx)
{
CL_UpdateBeams ();
CL_UpdateExplosions ();
CL_UpdateBeams (time, ctx);
CL_UpdateExplosions (time, ctx);
}
/*
CL_ParseParticleEffect
Parse an effect out of the server message
*/
void
CL_ParseParticleEffect (qmsg_t *net_message)
{
int i, count, color;
vec3_t org, dir;
MSG_ReadCoordV (net_message, org);
for (i = 0; i < 3; i++)
dir[i] = ((signed char) MSG_ReadByte (net_message)) * (15.0 / 16.0);
count = MSG_ReadByte (net_message);
color = MSG_ReadByte (net_message);
if (count == 255)
r_funcs->particles->R_ParticleExplosion (org);
else
r_funcs->particles->R_RunParticleEffect (org, dir, color, count);
}
void
@ -633,7 +719,7 @@ CL_ClearProjectiles (void)
Nails are passed as efficient temporary entities
*/
void
CL_ParseProjectiles (qboolean nail2)
CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx)
{
tent_t *tent;
tent_t *head = 0, **tail = &head;
@ -658,7 +744,7 @@ CL_ParseProjectiles (qboolean nail2)
tail = &tent->next;
pr = &tent->ent;
pr->renderer.model = cl.model_precache[cl_spikeindex];
pr->renderer.model = cl_spike;
pr->renderer.skin = 0;
pr->origin[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096;
pr->origin[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096;
@ -666,9 +752,9 @@ CL_ParseProjectiles (qboolean nail2)
pr->angles[0] = (bits[4] >> 4) * (360.0 / 16.0);
pr->angles[1] = bits[5] * (360.0 / 256.0);
pr->angles[2] = 0;
CL_TransformEntity (&tent->ent, tent->ent.angles, true);
CL_TransformEntity (&tent->ent, tent->ent.angles);
r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent);
r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent);
}
*tail = cl_projectiles;

View file

@ -304,10 +304,6 @@ void CL_Input_Init (void);
void CL_SendCmd (void);
void CL_SendMove (usercmd_t *cmd);
void CL_ParseParticleEffect (void);
void CL_ParseTEnt (void);
void CL_UpdateTEnts (void);
void CL_ClearState (void);
int CL_ReadFromServer (void);
@ -344,13 +340,7 @@ void V_SetContentsColor (int contents);
void V_PrepBlend (void);
// cl_tent
void CL_TEnts_Init (void);
void CL_ClearTEnts (void);
void CL_Init_Entity (struct entity_s *ent);
void CL_ParseTEnt (void);
void CL_SignonReply (void);
void CL_TransformEntity (struct entity_s *ent, const vec3_t
angles, qboolean force);
void CL_RelinkEntities (void);
void CL_ClearEnts (void);

View file

@ -70,7 +70,7 @@ nq_server_LIB_DEPS=$(nq_server_LIBFILES) $(nq_common_LIBFILES)
nq_source_libnq_client_a_SOURCES= \
nq/source/cl_chase.c nq/source/cl_cmd.c nq/source/cl_demo.c nq/source/cl_ents.c nq/source/cl_input.c nq/source/cl_main.c \
nq/source/cl_screen.c nq/source/cl_parse.c nq/source/cl_tent.c nq/source/cl_view.c nq/source/sbar.c
nq/source/cl_screen.c nq/source/cl_parse.c nq/source/cl_view.c nq/source/sbar.c
nq_source_libnq_server_a_SOURCES= \
nq/source/host.c nq/source/host_cmd.c nq/source/sv_cl_phys.c nq/source/sv_cvar.c nq/source/sv_main.c \

View file

@ -47,6 +47,8 @@
#include "compat.h"
#include "client/temp_entities.h"
#include "nq/include/chase.h"
#include "nq/include/client.h"
#include "nq/include/host.h"
@ -177,36 +179,6 @@ CL_LerpPoint (void)
return frac;
}
void
CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force)
{
union {
quat_t q;
vec4f_t v;
} rotation;
vec4f_t position;
vec4f_t scale;
VectorCopy (ent->origin, position);
position[3] = 1;
VectorSet (ent->scale, ent->scale, ent->scale, scale);
scale[3] = 1;
if (VectorIsZero (angles)) {
QuatSet (0, 0, 0, 1, rotation.q);
} else {
vec3_t ang;
VectorCopy (angles, ang);
if (ent->renderer.model && ent->renderer.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];
}
AngleQuat (ang, rotation.q);
}
Transform_SetLocalTransform (ent->transform, scale, rotation.v, position);
}
static void
CL_ModelEffects (entity_t *ent, int num, int glow_color)
{
@ -392,7 +364,7 @@ CL_RelinkEntities (void)
animation->pose1 = animation->pose2 = -1;
VectorCopy (new->origin, ent->origin);
if (!(model_flags & EF_ROTATE))
CL_TransformEntity (ent, new->angles, true);
CL_TransformEntity (ent, new->angles);
if (i != cl.viewentity || chase_active->int_val) {
if (ent->visibility.efrag) {
r_funcs->R_RemoveEfrags (ent);
@ -410,7 +382,7 @@ CL_RelinkEntities (void)
// assume a teleportation, not a motion
VectorCopy (new->origin, ent->origin);
if (!(model_flags & EF_ROTATE))
CL_TransformEntity (ent, new->angles, true);
CL_TransformEntity (ent, new->angles);
animation->pose1 = animation->pose2 = -1;
} else {
vec3_t angles, d;
@ -425,7 +397,7 @@ CL_RelinkEntities (void)
d[j] += 360;
}
VectorMultAdd (old->angles, f, d, angles);
CL_TransformEntity (ent, angles, false);
CL_TransformEntity (ent, angles);
}
}
if (i != cl.viewentity || chase_active->int_val) {
@ -445,7 +417,7 @@ CL_RelinkEntities (void)
vec3_t angles;
VectorCopy (new->angles, angles);
angles[YAW] = bobjrotate;
CL_TransformEntity (ent, angles, false);
CL_TransformEntity (ent, angles);
}
CL_EntityEffects (i, ent, new);
CL_NewDlight (i, ent->origin, new->effects, new->glow_size,

View file

@ -52,6 +52,8 @@
#include "clview.h"
#include "sbar.h"
#include "client/temp_entities.h"
#include "nq/include/chase.h"
#include "nq/include/cl_skin.h"
#include "nq/include/client.h"
@ -423,6 +425,10 @@ int
CL_ReadFromServer (void)
{
int ret;
TEntContext_t tentCtx = {
{VectorExpand (cl_entities[cl.viewentity].origin), 1},
cl.worldmodel, cl.viewentity
};
cl.oldtime = cl.time;
cl.time += host_frametime;
@ -442,7 +448,7 @@ CL_ReadFromServer (void)
Sys_Printf ("\n");
CL_RelinkEntities ();
CL_UpdateTEnts ();
CL_UpdateTEnts (cl.time, &tentCtx);
// bring the links up to date
return 0;

View file

@ -53,6 +53,8 @@
#include "QF/plugin/vid_render.h"
#include "client/temp_entities.h"
#include "compat.h"
#include "sbar.h"
@ -591,7 +593,7 @@ CL_ParseUpdate (int bits)
//VectorCopy (state->msg_origins[0], state->msg_origins[1]);
//VectorCopy (state->msg_origins[0], ent->origin);
//VectorCopy (state->msg_angles[0], state->msg_angles[1]);
//CL_TransformEntity (ent, state->msg_angles[0], true);
//CL_TransformEntity (ent, state->msg_angles[0]);
//state->forcelink = true;
cl_forcelink[num] = true;
}
@ -793,7 +795,7 @@ CL_ParseStatic (int version)
ent->renderer.colormod[3] = ENTALPHA_DECODE (baseline.alpha);
ent->scale = baseline.scale / 16.0;
VectorCopy (baseline.origin, ent->origin);
CL_TransformEntity (ent, baseline.angles, true);
CL_TransformEntity (ent, baseline.angles);
r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent);
}
@ -835,6 +837,11 @@ CL_ParseServerMessage (void)
static dstring_t *stuffbuf;
signon_t so;
TEntContext_t tentCtx = {
{VectorExpand (cl_entities[cl.viewentity].origin), 1},
cl.worldmodel, cl.viewentity
};
// if recording demos, copy the message out
if (cl_shownet->int_val == 1)
Sys_Printf ("%i ", net_message->message->cursize);
@ -1031,7 +1038,7 @@ CL_ParseServerMessage (void)
break;
case svc_particle:
CL_ParseParticleEffect ();
CL_ParseParticleEffect (net_message);
break;
case svc_damage:
@ -1051,7 +1058,7 @@ CL_ParseServerMessage (void)
break;
case svc_temp_entity:
CL_ParseTEnt ();
CL_ParseTEnt_nq (net_message, cl.time, &tentCtx);
break;
case svc_setpause:

View file

@ -1,630 +0,0 @@
/*
cl_tent.c
client side temporary entities
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 <math.h>
#include <stdlib.h>
#include "QF/entity.h"
#include "QF/model.h"
#include "QF/msg.h"
#include "QF/sound.h"
#include "QF/sys.h"
#include "QF/plugin/vid_render.h"
#include "compat.h"
#include "nq/include/client.h"
typedef struct tent_s {
struct tent_s *next;
entity_t ent;
} tent_t;
#define TEMP_BATCH 64
static tent_t *temp_entities = 0;
typedef struct {
int entity;
struct model_s *model;
float endtime;
vec3_t start, end;
tent_t *tents;
int seed;
} beam_t;
#define BEAM_SEED_INTERVAL 72
#define BEAM_SEED_PRIME 3191
typedef struct {
float start;
tent_t *tent;
} explosion_t;
typedef struct tent_obj_s {
struct tent_obj_s *next;
union {
beam_t beam;
explosion_t ex;
} to;
} tent_obj_t;
static tent_obj_t *tent_objects;
static tent_obj_t *cl_beams;
static tent_obj_t *cl_explosions;
static sfx_t *cl_sfx_wizhit;
static sfx_t *cl_sfx_knighthit;
static sfx_t *cl_sfx_tink1;
static sfx_t *cl_sfx_ric1;
static sfx_t *cl_sfx_ric2;
static sfx_t *cl_sfx_ric3;
static sfx_t *cl_sfx_r_exp3;
static model_t *cl_mod_beam;
static model_t *cl_mod_bolt;
static model_t *cl_mod_bolt2;
static model_t *cl_mod_bolt3;
static model_t *cl_spr_explod;
static void
CL_TEnts_Precache (int phase)
{
if (!phase)
return;
cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
cl_mod_bolt = Mod_ForName ("progs/bolt.mdl", true);
cl_mod_bolt2 = Mod_ForName ("progs/bolt2.mdl", true);
cl_mod_bolt3 = Mod_ForName ("progs/bolt3.mdl", true);
cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true);
cl_mod_beam = Mod_ForName ("progs/beam.mdl", false);
if (!cl_mod_beam)
cl_mod_beam = cl_mod_bolt;
}
void
CL_TEnts_Init (void)
{
QFS_GamedirCallback (CL_TEnts_Precache);
CL_TEnts_Precache (1);
}
void
CL_Init_Entity (entity_t *ent)
{
if (ent->transform) {
Transform_Delete (ent->transform);
}
memset (ent, 0, sizeof (*ent));
ent->transform = Transform_New (0);
ent->renderer.skin = 0;
QuatSet (1.0, 1.0, 1.0, 1.0, ent->renderer.colormod);
ent->scale = 1.0;
ent->animation.pose1 = ent->animation.pose2 = -1;
}
static tent_t *
new_temp_entity (void)
{
tent_t *tent;
if (!temp_entities) {
int i;
temp_entities = malloc (TEMP_BATCH * sizeof (tent_t));
for (i = 0; i < TEMP_BATCH - 1; i++) {
temp_entities[i].next = &temp_entities[i + 1];
temp_entities[i].ent.transform = 0;
}
temp_entities[i].next = 0;
temp_entities[i].ent.transform = 0;
}
tent = temp_entities;
temp_entities = tent->next;
tent->next = 0;
CL_Init_Entity (&tent->ent);
return tent;
}
static void
free_temp_entities (tent_t *tents)
{
tent_t **t = &tents;
while (*t)
t = &(*t)->next;
*t = temp_entities;
temp_entities = tents;
}
static tent_obj_t *
new_tent_object (void)
{
tent_obj_t *tobj;
if (!tent_objects) {
int i;
tent_objects = malloc (TEMP_BATCH * sizeof (tent_obj_t));
for (i = 0; i < TEMP_BATCH - 1; i++)
tent_objects[i].next = &tent_objects[i + 1];
tent_objects[i].next = 0;
}
tobj = tent_objects;
tent_objects = tobj->next;
tobj->next = 0;
return tobj;
}
static void
free_tent_objects (tent_obj_t *tobjs)
{
tent_obj_t **t = &tobjs;
while (*t)
t = &(*t)->next;
*t = tent_objects;
tent_objects = tobjs;
}
void
CL_ClearTEnts (void)
{
tent_t *t;
tent_obj_t *to;
for (to = cl_beams; to; to = to->next) {
for (t = to->to.beam.tents; t; t = t->next)
t->ent.visibility.efrag = 0;
free_temp_entities (to->to.beam.tents);
}
free_tent_objects (cl_beams);
cl_beams = 0;
for (to = cl_explosions; to; to = to->next) {
for (t = to->to.ex.tent; t; t = t->next)
t->ent.visibility.efrag = 0;
free_temp_entities (to->to.ex.tent);
}
free_tent_objects (cl_explosions);
cl_explosions = 0;
}
static inline void
beam_clear (beam_t *b)
{
if (b->tents) {
tent_t *t;
for (t = b->tents; t; t = t->next) {
r_funcs->R_RemoveEfrags (&t->ent);
t->ent.visibility.efrag = 0;
}
free_temp_entities (b->tents);
b->tents = 0;
}
}
static inline void
beam_setup (beam_t *b, qboolean transform)
{
tent_t *tent;
float forward, pitch, yaw, d;
int ent_count;
vec3_t dist, org, ang;
unsigned seed;
// calculate pitch and yaw
VectorSubtract (b->end, b->start, dist);
if (dist[1] == 0 && dist[0] == 0) {
yaw = 0;
if (dist[2] > 0)
pitch = 90;
else
pitch = 270;
} else {
yaw = (int) (atan2 (dist[1], dist[0]) * 180 / M_PI);
if (yaw < 0)
yaw += 360;
forward = sqrt (dist[0] * dist[0] + dist[1] * dist[1]);
pitch = (int) (atan2 (dist[2], forward) * 180 / M_PI);
if (pitch < 0)
pitch += 360;
}
// add new entities for the lightning
VectorCopy (b->start, org);
d = VectorNormalize (dist);
VectorScale (dist, 30, dist);
ent_count = ceil (d / 30);
d = 0;
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
BEAM_SEED_INTERVAL);
ang[ROLL] = 0;
while (ent_count--) {
tent = new_temp_entity ();
tent->next = b->tents;
b->tents = tent;
VectorMultAdd (org, d, dist, tent->ent.origin);
d += 1.0;
tent->ent.renderer.model = b->model;
ang[PITCH] = pitch;
ang[YAW] = yaw;
if (transform) {
seed = seed * BEAM_SEED_PRIME;
ang[ROLL] = seed % 360;
CL_TransformEntity (&tent->ent, ang, true);
}
VectorCopy (ang, tent->ent.angles);
r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent);
}
}
static void
CL_ParseBeam (model_t *m)
{
tent_obj_t *to;
beam_t *b;
int ent;
vec3_t start, end;
ent = MSG_ReadShort (net_message);
MSG_ReadCoordV (net_message, start);
MSG_ReadCoordV (net_message, end);
to = 0;
if (ent) {
for (to = cl_beams; to; to = to->next)
if (to->to.beam.entity == ent)
break;
}
if (!to) {
to = new_tent_object ();
to->next = cl_beams;
cl_beams = to;
to->to.beam.tents = 0;
to->to.beam.entity = ent;
}
b = &to->to.beam;
beam_clear (b);
b->model = m;
b->endtime = cl.time + 0.2;
b->seed = rand ();
VectorCopy (end, b->end);
if (b->entity != cl.viewentity) {
// this will be done in CL_UpdateBeams
VectorCopy (start, b->start);
beam_setup (b, true);
}
}
void
CL_ParseTEnt (void)
{
byte type;
dlight_t *dl;
tent_obj_t *to;
explosion_t *ex;
int colorStart, colorLength;
quat_t col;
vec3_t pos;
sfx_t *spike_sound[] = {
cl_sfx_ric3, cl_sfx_ric3, cl_sfx_ric2, cl_sfx_ric1,
};
type = MSG_ReadByte (net_message);
switch (type) {
case TE_WIZSPIKE: // spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_WizSpikeEffect (pos);
S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
break;
case TE_KNIGHTSPIKE: // spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_KnightSpikeEffect (pos);
S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
break;
case TE_SPIKE: // spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_SpikeEffect (pos);
{
int i;
sfx_t *sound;
i = (rand () % 20) - 16;
if (i >= 0)
sound = spike_sound[i];
else
sound = cl_sfx_tink1;
S_StartSound (-1, 0, sound, pos, 1, 1);
}
break;
case TE_SUPERSPIKE: // super spike hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_SuperSpikeEffect (pos);
{
int i;
sfx_t *sound;
i = (rand () % 20) - 16;
if (i >= 0)
sound = spike_sound[i];
else
sound = cl_sfx_tink1;
S_StartSound (-1, 0, sound, pos, 1, 1);
}
break;
case TE_EXPLOSION: // rocket explosion
// particles
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_ParticleExplosion (pos);
// light
dl = r_funcs->R_AllocDlight (0);
if (dl) {
VectorCopy (pos, dl->origin);
dl->radius = 350;
dl->die = cl.time + 0.5;
dl->decay = 300;
QuatSet (1.0, 0.5, 0.25, 0.7, dl->color);
}
// sound
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
// sprite
to = new_tent_object ();
to->next = cl_explosions;
cl_explosions = to;
ex = &to->to.ex;
ex->tent = new_temp_entity ();
VectorCopy (pos, ex->tent->ent.origin);
ex->start = cl.time;
//FIXME need better model management
if (!cl_spr_explod->cache.data)
cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true);
ex->tent->ent.renderer.model = cl_spr_explod;
CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true);
break;
case TE_TAREXPLOSION: // tarbaby explosion
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_BlobExplosion (pos);
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
break;
case TE_LIGHTNING1: // lightning bolts
CL_ParseBeam (cl_mod_bolt);
break;
case TE_LIGHTNING2: // lightning bolts
CL_ParseBeam (cl_mod_bolt2);
break;
case TE_LIGHTNING3: // lightning bolts
CL_ParseBeam (cl_mod_bolt3);
break;
case TE_LIGHTNING4NEH: // Nehahra lightning
CL_ParseBeam (Mod_ForName (MSG_ReadString (net_message), true));
break;
// PGM 01/21/97
case TE_BEAM: // grappling hook beam
CL_ParseBeam (cl_mod_beam);
break;
// PGM 01/21/97
case TE_LAVASPLASH:
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_LavaSplash (pos);
break;
case TE_TELEPORT:
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_TeleportSplash (pos);
break;
case TE_EXPLOSION2: // color mapped explosion
MSG_ReadCoordV (net_message, pos);
colorStart = MSG_ReadByte (net_message);
colorLength = MSG_ReadByte (net_message);
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
r_funcs->particles->R_ParticleExplosion2 (pos, colorStart,
colorLength);
dl = r_funcs->R_AllocDlight (0);
if (!dl)
break;
VectorCopy (pos, dl->origin);
dl->radius = 350;
dl->die = cl.time + 0.5;
dl->decay = 300;
colorStart = (colorStart + (rand () % colorLength)) * 3;
VectorScale (&r_data->vid->palette[colorStart], 1.0 / 255.0,
dl->color);
dl->color[3] = 0.7;
break;
case TE_EXPLOSION3: // Nehahra colored light explosion
MSG_ReadCoordV (net_message, pos);
MSG_ReadCoordV (net_message, col); // OUCH!
col[3] = 0.7;
r_funcs->particles->R_ParticleExplosion (pos);
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
dl = r_funcs->R_AllocDlight (0);
if (dl) {
VectorCopy (pos, dl->origin);
dl->radius = 350;
dl->die = cl.time + 0.5;
dl->decay = 300;
QuatCopy (col, dl->color);
}
break;
case TE_GUNSHOT: // bullet hitting wall
MSG_ReadCoordV (net_message, pos);
r_funcs->particles->R_GunshotEffect (pos, 20);
break;
default:
Sys_Error ("CL_ParseTEnt: bad type %d", type);
}
}
static void
CL_UpdateBeams (void)
{
tent_obj_t **to;
beam_t *b;
unsigned seed;
tent_t *t;
// update lightning
for (to = &cl_beams; *to; ) {
b = &(*to)->to.beam;
if (!b->endtime)
continue;
if (!b->model || b->endtime < cl.time) {
tent_obj_t *_to;
b->endtime = 0;
beam_clear (b);
_to = *to;
*to = _to->next;
_to->next = tent_objects;
tent_objects = _to;
continue;
}
to = &(*to)->next;
// if coming from the player, update the start position
if (b->entity == cl.viewentity) {
beam_clear (b);
VectorCopy (cl_entities[cl.viewentity].origin, b->start);
beam_setup (b, false);
}
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
BEAM_SEED_INTERVAL);
// add new entities for the lightning
for (t = b->tents; t; t = t->next) {
seed = seed * BEAM_SEED_PRIME;
t->ent.angles[ROLL] = seed % 360;
CL_TransformEntity (&t->ent, t->ent.angles, true);
}
}
}
static void
CL_UpdateExplosions (void)
{
int f;
tent_obj_t **to;
explosion_t *ex;
entity_t *ent;
for (to = &cl_explosions; *to; ) {
ex = &(*to)->to.ex;
ent = &ex->tent->ent;
f = 10 * (cl.time - ex->start);
if (f >= ent->renderer.model->numframes) {
tent_obj_t *_to;
r_funcs->R_RemoveEfrags (ent);
ent->visibility.efrag = 0;
free_temp_entities (ex->tent);
_to = *to;
*to = _to->next;
_to->next = tent_objects;
tent_objects = _to;
continue;
}
to = &(*to)->next;
ent->animation.frame = f;
if (!ent->visibility.efrag)
r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent);
}
}
void
CL_UpdateTEnts (void)
{
CL_UpdateBeams ();
CL_UpdateExplosions ();
}
/*
CL_ParseParticleEffect
Parse an effect out of the server message
*/
void
CL_ParseParticleEffect (void)
{
int i, count, color;
vec3_t org, dir;
MSG_ReadCoordV (net_message, org);
for (i = 0; i < 3; i++)
dir[i] = ((signed char) MSG_ReadByte (net_message)) * (15.0 / 16.0);
count = MSG_ReadByte (net_message);
color = MSG_ReadByte (net_message);
if (count == 255)
r_funcs->particles->R_ParticleExplosion (org);
else
r_funcs->particles->R_RunParticleEffect (org, dir, color, count);
}

View file

@ -728,7 +728,7 @@ V_CalcRefdef (void)
if (cl.chase && chase_active->int_val)
Chase_Update ();
CL_TransformEntity (view, view->angles, true);
CL_TransformEntity (view, view->angles);
}
/*

View file

@ -11,7 +11,6 @@ EXTRA_DIST += \
qw/include/cl_pred.h \
qw/include/cl_skin.h \
qw/include/cl_slist.h \
qw/include/cl_tent.h \
qw/include/client.h \
qw/include/crudefile.h \
qw/include/game.h \

View file

@ -34,11 +34,9 @@
void CL_SetSolidPlayers (int playernum);
void CL_ClearPredict (void);
void CL_SetUpPlayerPrediction(qboolean dopred);
void CL_TransformEntity (struct entity_s * ent, const vec3_t angles,
qboolean force);
void CL_ClearEnts (void);
void CL_EmitEntities (void);
void CL_ClearProjectiles (void);
void CL_ParseProjectiles (qboolean nail2);
void CL_ParsePacketEntities (qboolean delta);
void CL_SetSolidEntities (void);
void CL_ParsePlayerinfo (void);

View file

@ -40,7 +40,6 @@ extern int parsecountmod;
extern double parsecounttime;
extern int cl_playerindex;
extern int cl_flagindex;
extern int cl_spikeindex;
extern int viewentity;
extern int cl_h_playerindex;
extern int cl_gib1index;

View file

@ -1,38 +0,0 @@
/*
client.h
Client definitions
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
*/
#ifndef _CL_TENT_H
#define _CL_TENT_H
void CL_TEnts_Init (void);
void CL_ClearEnts (void);
void CL_ClearTEnts (void);
void CL_Init_Entity (struct entity_s *ent);
void CL_ParseTEnt (void);
void CL_UpdateTEnts (void);
#endif

View file

@ -103,7 +103,7 @@ qw_source_libqw_client_a_SOURCES= \
qw/source/cl_cam.c qw/source/cl_chase.c qw/source/cl_chat.c qw/source/cl_cmd.c qw/source/cl_cvar.c qw/source/cl_demo.c \
qw/source/cl_entparse.c qw/source/cl_ents.c qw/source/cl_http.c qw/source/cl_input.c qw/source/cl_main.c qw/source/cl_ngraph.c \
qw/source/cl_parse.c qw/source/cl_pred.c qw/source/cl_rss.c qw/source/cl_screen.c qw/source/cl_skin.c qw/source/cl_slist.c \
qw/source/cl_tent.c qw/source/cl_view.c \
qw/source/cl_view.c \
qw/source/locs.c qw/source/sbar.c qw/source/teamplay.c
# Software-rendering clients

View file

@ -45,6 +45,8 @@
#include "compat.h"
#include "clview.h"
#include "client/temp_entities.h"
#include "qw/msg_ucmd.h"
#include "qw/pmove.h"
#include "qw/bothdefs.h"
@ -54,7 +56,6 @@
#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"
static struct predicted_player {

View file

@ -47,6 +47,8 @@
#include "clview.h"
#include "d_iface.h"
#include "client/temp_entities.h"
#include "qw/bothdefs.h"
#include "qw/msg_ucmd.h"
#include "qw/pmove.h"
@ -57,7 +59,6 @@
#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];
@ -170,36 +171,6 @@ is_gib (entity_state_t *s1)
return 0;
}
void
CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force)
{
union {
quat_t q;
vec4f_t v;
} rotation;
vec4f_t position;
vec4f_t scale;
VectorCopy (ent->origin, position);
position[3] = 1;
VectorSet (ent->scale, ent->scale, ent->scale, scale);
scale[3] = 1;
if (VectorIsZero (angles)) {
QuatSet (0, 0, 0, 1, rotation.q);
} else {
vec3_t ang;
VectorCopy (angles, ang);
if (ent->renderer.model && ent->renderer.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];
}
AngleQuat (ang, rotation.q);
}
Transform_SetLocalTransform (ent->transform, scale, rotation.v, position);
}
static void
CL_ModelEffects (entity_t *ent, int num, int glow_color)
{
@ -342,7 +313,7 @@ CL_LinkPacketEntities (void)
animation->pose1 = animation->pose2 = -1;
VectorCopy (new->origin, ent->origin);
if (!(renderer->model->flags & EF_ROTATE))
CL_TransformEntity (ent, new->angles, true);
CL_TransformEntity (ent, new->angles);
if (i != cl.viewentity || chase_active->int_val) {
if (ent->visibility.efrag) {
r_funcs->R_RemoveEfrags (ent);
@ -360,7 +331,7 @@ CL_LinkPacketEntities (void)
// assume a teleportation, not a motion
VectorCopy (new->origin, ent->origin);
if (!(renderer->model->flags & EF_ROTATE)) {
CL_TransformEntity (ent, new->angles, true);
CL_TransformEntity (ent, new->angles);
}
animation->pose1 = animation->pose2 = -1;
} else {
@ -376,7 +347,7 @@ CL_LinkPacketEntities (void)
d[j] += 360;
}
VectorMultAdd (old->angles, f, d, angles);
CL_TransformEntity (ent, angles, false);
CL_TransformEntity (ent, angles);
}
}
if (i != cl.viewentity || chase_active->int_val) {
@ -400,7 +371,7 @@ CL_LinkPacketEntities (void)
angles[PITCH] = 0;
angles[YAW] = anglemod (100 * cl.time);
angles[ROLL] = 0;
CL_TransformEntity (ent, angles, false);
CL_TransformEntity (ent, angles);
}
//CL_EntityEffects (i, ent, new);
//CL_NewDlight (i, ent->origin, new->effects, 0, 0);
@ -567,7 +538,7 @@ CL_LinkPlayers (void)
ent->animation.frame = state->pls.frame;
ent->renderer.skinnum = state->pls.skinnum;
CL_TransformEntity (ent, ang, false);
CL_TransformEntity (ent, ang);
ent->renderer.min_light = 0;
ent->renderer.fullbright = 0;
@ -611,9 +582,13 @@ CL_EmitEntities (void)
if (!cl.validsequence)
return;
TEntContext_t tentCtx = {
{VectorExpand (cl.simorg), 1}, cl.worldmodel, cl.viewentity
};
CL_LinkPlayers ();
CL_LinkPacketEntities ();
CL_UpdateTEnts ();
CL_UpdateTEnts (cl.time, &tentCtx);
if (cl_draw_locs->int_val) {
//FIXME custom ent rendering code would be nice
dlight_t *dl;

View file

@ -96,6 +96,8 @@
#include "compat.h"
#include "sbar.h"
#include "client/temp_entities.h"
#include "qw/bothdefs.h"
#include "qw/pmove.h"
@ -110,7 +112,6 @@
#include "qw/include/cl_pred.h"
#include "qw/include/cl_skin.h"
#include "qw/include/cl_slist.h"
#include "qw/include/cl_tent.h"
#include "qw/include/client.h"
#include "qw/include/game.h"
#include "qw/include/host.h"

View file

@ -65,6 +65,8 @@
#include "clview.h"
#include "sbar.h"
#include "client/temp_entities.h"
#include "qw/bothdefs.h"
#include "qw/pmove.h"
#include "qw/protocol.h"
@ -77,7 +79,6 @@
#include "qw/include/cl_main.h"
#include "qw/include/cl_parse.h"
#include "qw/include/cl_skin.h"
#include "qw/include/cl_tent.h"
#include "qw/include/client.h"
#include "qw/include/host.h"
#include "qw/include/map_cfg.h"
@ -161,7 +162,7 @@ int oldparsecountmod;
int parsecountmod;
double parsecounttime;
int cl_spikeindex, cl_playerindex, cl_flagindex;
int cl_playerindex, cl_flagindex;
int cl_h_playerindex, cl_gib1index, cl_gib2index, cl_gib3index;
int packet_latency[NET_TIMINGS];
@ -437,7 +438,6 @@ Sound_NextDownload (void)
// done with sounds, request models now
memset (cl.model_precache, 0, sizeof (cl.model_precache));
cl_playerindex = -1;
cl_spikeindex = -1;
cl_flagindex = -1;
cl_h_playerindex = -1;
cl_gib1index = cl_gib2index = cl_gib3index = -1;
@ -906,9 +906,7 @@ CL_ParseModellist (void)
Host_Error ("Server sent too many model_precache");
strcpy (cl.model_name[cl.nummodels], str);
if (!strcmp (cl.model_name[cl.nummodels], "progs/spike.mdl"))
cl_spikeindex = cl.nummodels;
else if (!strcmp (cl.model_name[cl.nummodels], "progs/player.mdl"))
if (!strcmp (cl.model_name[cl.nummodels], "progs/player.mdl"))
cl_playerindex = cl.nummodels;
else if (!strcmp (cl.model_name[cl.nummodels], "progs/flag.mdl"))
cl_flagindex = cl.nummodels;
@ -984,7 +982,7 @@ CL_ParseStatic (void)
ent->renderer.skinnum = es.skinnum;
VectorCopy (es.origin, ent->origin);
CL_TransformEntity (ent, es.angles, true);
CL_TransformEntity (ent, es.angles);
r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent);
}
@ -1305,6 +1303,9 @@ CL_ParseServerMessage (void)
int cmd = 0, i, j;
const char *str;
static dstring_t *stuffbuf;
TEntContext_t tentCtx = {
{VectorExpand (cl.simorg), 1}, cl.worldmodel, cl.viewentity
};
received_framecount = host_framecount;
cl.last_servermessage = realtime;
@ -1507,7 +1508,7 @@ CL_ParseServerMessage (void)
break;
case svc_temp_entity:
CL_ParseTEnt ();
CL_ParseTEnt_qw (net_message, cl.time, &tentCtx);
break;
case svc_setpause:
@ -1639,7 +1640,7 @@ CL_ParseServerMessage (void)
break;
case svc_nails:
CL_ParseProjectiles (false);
CL_ParseProjectiles (net_message, false, &tentCtx);
break;
case svc_chokecount: // some preceding packets were choked
@ -1690,7 +1691,7 @@ CL_ParseServerMessage (void)
break;
case svc_nails2: // FIXME from qwex
CL_ParseProjectiles (true);
CL_ParseProjectiles (net_message, true, &tentCtx);
break;
}
}

View file

@ -731,7 +731,7 @@ V_CalcRefdef (void)
if (cl.chase && chase_active->int_val)
Chase_Update ();
CL_TransformEntity (view, view->angles, true);
CL_TransformEntity (view, view->angles);
}
static void