2004-08-23 00:15:46 +00:00
/*
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
2005-02-06 02:47:36 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-23 00:15:46 +00:00
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 the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// cl_ents.c -- entity parsing and management
# include "quakedef.h"
2004-10-19 16:10:14 +00:00
# include "particles.h"
2004-08-23 00:15:46 +00:00
extern cvar_t cl_predict_players ;
extern cvar_t cl_predict_players2 ;
extern cvar_t cl_solid_players ;
extern cvar_t cl_item_bobbing ;
2005-01-17 17:40:37 +00:00
extern cvar_t r_rocketlight ;
extern cvar_t r_lightflicker ;
extern cvar_t cl_r2g ;
extern cvar_t r_powerupglow ;
2005-04-16 16:21:27 +00:00
extern cvar_t v_powerupshell ;
2005-04-26 16:04:12 +00:00
extern cvar_t cl_nolerp ;
2005-01-18 20:15:20 +00:00
extern cvar_t cl_gibfilter , cl_deadbodyfilter ;
2004-08-23 00:15:46 +00:00
extern int cl_playerindex ;
static struct predicted_player {
int flags ;
int frame ;
int oldframe ;
float lerptime ;
qboolean active ;
vec3_t origin ; // predicted origin
2004-12-15 17:47:42 +00:00
vec3_t oldo ;
vec3_t olda ;
vec3_t oldv ;
qboolean predict ;
player_state_t * oldstate ;
2004-08-23 00:15:46 +00:00
} predicted_players [ MAX_CLIENTS ] ;
float newlerprate ;
2005-01-18 20:15:20 +00:00
extern int cl_playerindex , cl_h_playerindex , cl_rocketindex , cl_grenadeindex , cl_gib1index , cl_gib2index , cl_gib3index ;
qboolean CL_FilterModelindex ( int modelindex , int frame )
{
if ( modelindex = = cl_playerindex )
{
if ( cl_deadbodyfilter . value = = 2 )
{
if ( frame > = 41 & & frame < = 102 )
return true ;
}
else if ( cl_deadbodyfilter . value )
{
if ( frame = = 49 | | frame = = 60 | | frame = = 69 | | frame = = 84 | | frame = = 93 | | frame = = 102 )
return true ;
}
}
if ( cl_gibfilter . value & & (
2005-02-06 02:47:36 +00:00
modelindex = = cl_h_playerindex | |
2005-01-18 20:15:20 +00:00
modelindex = = cl_gib1index | |
modelindex = = cl_gib2index | |
modelindex = = cl_gib3index ) )
return true ;
return false ;
}
2005-01-17 17:40:37 +00:00
2004-08-23 00:15:46 +00:00
//============================================================
/*
= = = = = = = = = = = = = = =
CL_AllocDlight
= = = = = = = = = = = = = = =
*/
dlight_t * CL_AllocDlight ( int key )
{
int i ;
dlight_t * dl ;
// first look for an exact key match
if ( key )
{
dl = cl_dlights ;
for ( i = 0 ; i < MAX_DLIGHTS ; i + + , dl + + )
{
if ( dl - > key = = key )
{
memset ( dl , 0 , sizeof ( * dl ) ) ;
dl - > key = key ;
return dl ;
}
}
}
// then look for anything else
dl = cl_dlights ;
for ( i = 0 ; i < MAX_DLIGHTS ; i + + , dl + + )
{
2004-11-27 08:16:25 +00:00
if ( ! dl - > radius )
2004-08-23 00:15:46 +00:00
{
memset ( dl , 0 , sizeof ( * dl ) ) ;
dl - > key = key ;
return dl ;
}
}
dl = & cl_dlights [ 0 ] ;
memset ( dl , 0 , sizeof ( * dl ) ) ;
dl - > key = key ;
return dl ;
}
/*
= = = = = = = = = = = = = = =
CL_NewDlight
= = = = = = = = = = = = = = =
*/
dlight_t * CL_NewDlight ( int key , float x , float y , float z , float radius , float time ,
int type )
{
dlight_t * dl ;
dl = CL_AllocDlight ( key ) ;
dl - > origin [ 0 ] = x ;
dl - > origin [ 1 ] = y ;
dl - > origin [ 2 ] = z ;
dl - > radius = radius ;
2004-11-27 08:16:25 +00:00
dl - > die = ( float ) cl . time + time ;
2004-08-23 00:15:46 +00:00
if ( type = = 0 ) {
dl - > color [ 0 ] = 0.2 ;
dl - > color [ 1 ] = 0.1 ;
dl - > color [ 2 ] = 0.05 ;
} else if ( type = = 1 ) {
dl - > color [ 0 ] = 0.05 ;
dl - > color [ 1 ] = 0.05 ;
dl - > color [ 2 ] = 0.3 ;
} else if ( type = = 2 ) {
dl - > color [ 0 ] = 0.5 ;
dl - > color [ 1 ] = 0.05 ;
dl - > color [ 2 ] = 0.05 ;
} else if ( type = = 3 ) {
dl - > color [ 0 ] = 0.5 ;
dl - > color [ 1 ] = 0.05 ;
dl - > color [ 2 ] = 0.4 ;
}
return dl ;
}
void CL_NewDlightRGB ( int key , float x , float y , float z , float radius , float time ,
float r , float g , float b )
{
dlight_t * dl ;
dl = CL_AllocDlight ( key ) ;
dl - > origin [ 0 ] = x ;
dl - > origin [ 1 ] = y ;
dl - > origin [ 2 ] = z ;
dl - > radius = radius ;
dl - > die = cl . time + time ;
dl - > color [ 0 ] = r ;
dl - > color [ 1 ] = g ;
dl - > color [ 2 ] = b ;
}
/*
= = = = = = = = = = = = = = =
CL_DecayLights
= = = = = = = = = = = = = = =
*/
void CL_DecayLights ( void )
{
int i ;
dlight_t * dl ;
if ( cl . paused ) //DON'T DO IT!!!
return ;
dl = cl_dlights ;
for ( i = 0 ; i < MAX_DLIGHTS ; i + + , dl + + )
{
2004-11-27 08:16:25 +00:00
if ( ! dl - > radius )
2004-08-23 00:15:46 +00:00
continue ;
2004-11-27 08:16:25 +00:00
if ( dl - > die < ( float ) cl . time )
{
dl - > radius = 0 ;
continue ;
}
2005-02-06 02:47:36 +00:00
2004-08-23 00:15:46 +00:00
dl - > radius - = host_frametime * dl - > decay ;
if ( dl - > radius < 0 )
dl - > radius = 0 ;
if ( dl - > channelfade [ 0 ] )
{
2005-02-06 02:47:36 +00:00
dl - > color [ 0 ] - = host_frametime * dl - > channelfade [ 0 ] ;
2004-08-23 00:15:46 +00:00
if ( dl - > color [ 0 ] < 0 )
dl - > color [ 0 ] = 0 ;
}
if ( dl - > channelfade [ 1 ] )
{
2005-02-06 02:47:36 +00:00
dl - > color [ 1 ] - = host_frametime * dl - > channelfade [ 1 ] ;
2004-08-23 00:15:46 +00:00
if ( dl - > color [ 1 ] < 0 )
dl - > color [ 1 ] = 0 ;
}
if ( dl - > channelfade [ 2 ] )
{
2005-02-06 02:47:36 +00:00
dl - > color [ 2 ] - = host_frametime * dl - > channelfade [ 2 ] ;
2004-08-23 00:15:46 +00:00
if ( dl - > color [ 2 ] < 0 )
dl - > color [ 2 ] = 0 ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
PACKET ENTITY PARSING / LINKING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
CL_ParseDelta
Can go from either a baseline or a previous packet_entity
= = = = = = = = = = = = = = = = = =
*/
int bitcounts [ 32 ] ; /// just for protocol profiling
void CL_ParseDelta ( entity_state_t * from , entity_state_t * to , int bits , qboolean new )
{
int i ;
# ifdef PROTOCOLEXTENSIONS
int morebits = 0 ;
# endif
// set everything to the state we are delta'ing from
* to = * from ;
to - > number = bits & 511 ;
bits & = ~ 511 ;
if ( bits & U_MOREBITS )
{ // read in the low order bits
i = MSG_ReadByte ( ) ;
bits | = i ;
}
// count the bits for net profiling
for ( i = 0 ; i < 16 ; i + + )
if ( bits & ( 1 < < i ) )
bitcounts [ i ] + + ;
# ifdef PROTOCOLEXTENSIONS
if ( bits & U_EVENMORE & & cls . fteprotocolextensions )
morebits = MSG_ReadByte ( ) ;
if ( morebits & U_YETMORE )
morebits | = MSG_ReadByte ( ) < < 8 ;
# endif
if ( bits & U_MODEL )
to - > modelindex = MSG_ReadByte ( ) ;
if ( bits & U_FRAME )
to - > frame = MSG_ReadByte ( ) ;
if ( bits & U_COLORMAP )
to - > colormap = MSG_ReadByte ( ) ;
if ( bits & U_SKIN )
to - > skinnum = MSG_ReadByte ( ) ;
if ( bits & U_EFFECTS )
2005-08-26 22:56:51 +00:00
to - > effects = ( to - > effects & 0xff00 ) | MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
if ( bits & U_ORIGIN1 )
to - > origin [ 0 ] = MSG_ReadCoord ( ) ;
2005-02-06 02:47:36 +00:00
2004-08-23 00:15:46 +00:00
if ( bits & U_ANGLE1 )
to - > angles [ 0 ] = MSG_ReadAngle ( ) ;
if ( bits & U_ORIGIN2 )
to - > origin [ 1 ] = MSG_ReadCoord ( ) ;
2005-02-06 02:47:36 +00:00
2004-08-23 00:15:46 +00:00
if ( bits & U_ANGLE2 )
to - > angles [ 1 ] = MSG_ReadAngle ( ) ;
if ( bits & U_ORIGIN3 )
to - > origin [ 2 ] = MSG_ReadCoord ( ) ;
2005-02-06 02:47:36 +00:00
2004-08-23 00:15:46 +00:00
if ( bits & U_ANGLE3 )
to - > angles [ 2 ] = MSG_ReadAngle ( ) ;
if ( bits & U_SOLID )
{
// FIXME
}
# ifdef PEXT_SCALE
if ( morebits & U_SCALE & & cls . fteprotocolextensions & PEXT_SCALE )
2005-07-01 19:23:00 +00:00
to - > scale = MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_TRANS
if ( morebits & U_TRANS & & cls . fteprotocolextensions & PEXT_TRANS )
2005-07-01 19:23:00 +00:00
to - > trans = MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_FATNESS
if ( morebits & U_FATNESS & & cls . fteprotocolextensions & PEXT_FATNESS )
2005-07-01 19:23:00 +00:00
to - > fatness = MSG_ReadChar ( ) ;
2004-08-23 00:15:46 +00:00
# endif
if ( morebits & U_DRAWFLAGS & & cls . fteprotocolextensions & PEXT_HEXEN2 )
2005-05-15 18:49:04 +00:00
to - > hexen2flags = MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
if ( morebits & U_ABSLIGHT & & cls . fteprotocolextensions & PEXT_HEXEN2 )
to - > abslight = MSG_ReadByte ( ) ;
if ( morebits & U_ENTITYDBL )
to - > number + = 512 ;
if ( morebits & U_ENTITYDBL2 )
to - > number + = 1024 ;
if ( morebits & U_MODELDBL )
to - > modelindex + = 256 ;
2005-05-15 18:49:04 +00:00
if ( morebits & U_DPFLAGS ) // && cls.fteprotocolextensions & PEXT_DPFLAGS)
{
// these are bits for the 'flags' field of the entity_state_t
# define RENDER_STEP 1
# define RENDER_GLOWTRAIL 2
# define RENDER_VIEWMODEL 4
# define RENDER_EXTERIORMODEL 8
# define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth
# define RENDER_COLORMAPPED 32
# define RENDER_SHADOW 65536 // cast shadow
# define RENDER_LIGHT 131072 // receive light
# define RENDER_TRANSPARENT 262144 // can't light during opaque stage
i = MSG_ReadByte ( ) ;
to - > flags = 0 ;
if ( i & RENDER_VIEWMODEL )
to - > flags | = Q2RF_WEAPONMODEL | Q2RF_MINLIGHT | Q2RF_DEPTHHACK ;
if ( i & RENDER_EXTERIORMODEL )
to - > flags | = Q2RF_EXTERNALMODEL ;
}
2005-07-01 19:23:00 +00:00
if ( morebits & U_TAGINFO )
{
to - > tagentity = MSG_ReadShort ( ) ;
to - > tagindex = MSG_ReadShort ( ) ;
}
2005-08-07 18:08:13 +00:00
if ( morebits & U_LIGHT )
{
to - > light [ 0 ] = MSG_ReadShort ( ) ;
to - > light [ 1 ] = MSG_ReadShort ( ) ;
to - > light [ 2 ] = MSG_ReadShort ( ) ;
to - > light [ 3 ] = MSG_ReadShort ( ) ;
to - > lightstyle = MSG_ReadByte ( ) ;
to - > lightpflags = MSG_ReadByte ( ) ;
}
2005-05-15 18:49:04 +00:00
2005-08-26 22:56:51 +00:00
if ( morebits & U_EFFECTS16 )
to - > effects = ( to - > effects & 0x00ff ) | ( MSG_ReadByte ( ) < < 8 ) ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = = =
FlushEntityPacket
= = = = = = = = = = = = = = = = =
*/
void FlushEntityPacket ( void )
{
int word ;
entity_state_t olde , newe ;
Con_DPrintf ( " FlushEntityPacket \n " ) ;
memset ( & olde , 0 , sizeof ( olde ) ) ;
cl . validsequence = 0 ; // can't render a frame
cl . frames [ cls . netchan . incoming_sequence & UPDATE_MASK ] . invalid = true ;
// read it all, but ignore it
while ( 1 )
{
word = ( unsigned short ) MSG_ReadShort ( ) ;
if ( msg_badread )
{ // something didn't parse right...
Host_EndGame ( " msg_badread in packetentities " ) ;
return ;
}
if ( ! word )
break ; // done
CL_ParseDelta ( & olde , & newe , word , true ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
CL_ParsePacketEntities
An svc_packetentities has just been parsed , deal with the
rest of the data stream .
= = = = = = = = = = = = = = = = = =
*/
void CL_ParsePacketEntities ( qboolean delta )
{
int oldpacket , newpacket ;
packet_entities_t * oldp , * newp , dummy ;
int oldindex , newindex ;
int word , newnum , oldnum ;
qboolean full ;
2004-12-08 04:14:52 +00:00
int from ;
2005-11-30 01:20:53 +00:00
if ( ! ( cls . fteprotocolextensions & PEXT_ACCURATETIMINGS ) )
{
cl . oldgametime = cl . gametime ;
cl . oldgametimemark = cl . gametimemark ;
cl . gametime = realtime ;
cl . gametimemark = realtime ;
}
2004-08-23 00:15:46 +00:00
newpacket = cls . netchan . incoming_sequence & UPDATE_MASK ;
newp = & cl . frames [ newpacket ] . packet_entities ;
cl . frames [ newpacket ] . invalid = false ;
2005-11-26 03:02:55 +00:00
newp - > servertime = cl . gametime ;
2004-08-23 00:15:46 +00:00
if ( delta )
{
from = MSG_ReadByte ( ) ;
oldpacket = cl . frames [ newpacket ] . delta_sequence ;
if ( cls . demoplayback = = DPB_MVD )
from = oldpacket = cls . netchan . incoming_sequence - 1 ;
2004-12-08 04:14:52 +00:00
if ( cls . netchan . outgoing_sequence - cls . netchan . incoming_sequence > = UPDATE_BACKUP - 1 ) {
// there are no valid frames left, so drop it
FlushEntityPacket ( ) ;
cl . validsequence = 0 ;
return ;
}
if ( ( from & UPDATE_MASK ) ! = ( oldpacket & UPDATE_MASK ) ) {
2004-08-23 00:15:46 +00:00
Con_DPrintf ( " WARNING: from mismatch \n " ) ;
2005-05-13 10:42:48 +00:00
// FlushEntityPacket ();
// cl.validsequence = 0;
// return;
2004-12-08 04:14:52 +00:00
}
2004-08-23 00:15:46 +00:00
2004-12-08 04:14:52 +00:00
if ( cls . netchan . outgoing_sequence - oldpacket > = UPDATE_BACKUP - 1 ) {
// we can't use this, it is too old
2004-08-23 00:15:46 +00:00
FlushEntityPacket ( ) ;
2004-12-08 04:14:52 +00:00
// don't clear cl.validsequence, so that frames can still be rendered;
// it is possible that a fresh packet will be received before
// (outgoing_sequence - incoming_sequence) exceeds UPDATE_BACKUP - 1
2004-08-23 00:15:46 +00:00
return ;
}
2004-12-08 04:14:52 +00:00
oldp = & cl . frames [ oldpacket & UPDATE_MASK ] . packet_entities ;
full = false ;
2004-08-23 00:15:46 +00:00
}
else
{ // this is a full update that we can start delta compressing from now
oldp = & dummy ;
dummy . num_entities = 0 ;
full = true ;
}
2004-12-08 04:14:52 +00:00
cl . oldvalidsequence = cl . validsequence ;
cl . validsequence = cls . netchan . incoming_sequence ;
2004-08-23 00:15:46 +00:00
oldindex = 0 ;
newindex = 0 ;
newp - > num_entities = 0 ;
while ( 1 )
{
word = ( unsigned short ) MSG_ReadShort ( ) ;
if ( msg_badread )
{ // something didn't parse right...
Host_EndGame ( " msg_badread in packetentities " ) ;
return ;
}
if ( ! word )
{
while ( oldindex < oldp - > num_entities )
{ // copy all the rest of the entities from the old packet
//Con_Printf ("copy %i\n", oldp->entities[oldindex].number);
if ( newindex > = newp - > max_entities )
{
newp - > max_entities = newindex + 1 ;
newp - > entities = BZ_Realloc ( newp - > entities , sizeof ( entity_state_t ) * newp - > max_entities ) ;
}
if ( oldindex > = oldp - > max_entities )
Host_EndGame ( " Old packet entity too big \n " ) ;
newp - > entities [ newindex ] = oldp - > entities [ oldindex ] ;
newindex + + ;
oldindex + + ;
}
break ;
}
newnum = word & 511 ;
if ( word & U_MOREBITS )
{
int oldpos = msg_readcount ;
int excessive ;
excessive = MSG_ReadByte ( ) ;
if ( excessive & U_EVENMORE )
{
excessive = MSG_ReadByte ( ) ;
if ( excessive & U_ENTITYDBL )
newnum + = 512 ;
if ( excessive & U_ENTITYDBL2 )
newnum + = 1024 ;
2005-02-06 02:47:36 +00:00
}
2004-08-23 00:15:46 +00:00
msg_readcount = oldpos ; //undo the read...
}
oldnum = oldindex > = oldp - > num_entities ? 9999 : oldp - > entities [ oldindex ] . number ;
while ( newnum > oldnum )
{
if ( full )
{
Con_Printf ( " WARNING: oldcopy on full update " ) ;
FlushEntityPacket ( ) ;
return ;
}
//Con_Printf ("copy %i\n", oldnum);
// copy one of the old entities over to the new packet unchanged
if ( newindex > = newp - > max_entities )
{
newp - > max_entities = newindex + 1 ;
newp - > entities = BZ_Realloc ( newp - > entities , sizeof ( entity_state_t ) * newp - > max_entities ) ;
}
if ( oldindex > = oldp - > max_entities )
Host_EndGame ( " Old packet entity too big \n " ) ;
newp - > entities [ newindex ] = oldp - > entities [ oldindex ] ;
newindex + + ;
oldindex + + ;
oldnum = oldindex > = oldp - > num_entities ? 9999 : oldp - > entities [ oldindex ] . number ;
}
if ( newnum < oldnum )
{ // new from baseline
//Con_Printf ("baseline %i\n", newnum);
if ( word & U_REMOVE )
2005-10-20 00:04:57 +00:00
{ //really read the extra entity number if required
if ( word & U_MOREBITS )
if ( MSG_ReadByte ( ) & U_EVENMORE )
MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
if ( full )
{
cl . validsequence = 0 ;
Con_Printf ( " WARNING: U_REMOVE on full update \n " ) ;
FlushEntityPacket ( ) ;
return ;
}
continue ;
}
if ( newindex > = newp - > max_entities )
{
newp - > max_entities = newindex + 1 ;
newp - > entities = BZ_Realloc ( newp - > entities , sizeof ( entity_state_t ) * newp - > max_entities ) ;
}
CL_ParseDelta ( & cl_baselines [ newnum ] , & newp - > entities [ newindex ] , word , true ) ;
newindex + + ;
continue ;
}
if ( newnum = = oldnum )
{ // delta from previous
if ( full )
{
cl . validsequence = 0 ;
Con_Printf ( " WARNING: delta on full update " ) ;
}
if ( word & U_REMOVE )
{
2005-10-20 00:04:57 +00:00
if ( word & U_MOREBITS )
if ( MSG_ReadByte ( ) & U_EVENMORE )
MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
oldindex + + ;
continue ;
}
if ( newindex > = newp - > max_entities )
{
newp - > max_entities = newindex + 1 ;
newp - > entities = BZ_Realloc ( newp - > entities , sizeof ( entity_state_t ) * newp - > max_entities ) ;
}
//Con_Printf ("delta %i\n",newnum);
CL_ParseDelta ( & oldp - > entities [ oldindex ] , & newp - > entities [ newindex ] , word , false ) ;
newindex + + ;
oldindex + + ;
}
}
newp - > num_entities = newindex ;
}
2004-11-29 01:21:00 +00:00
2004-08-23 00:15:46 +00:00
entity_state_t * CL_FindOldPacketEntity ( int num )
{
int pnum ;
entity_state_t * s1 ;
packet_entities_t * pack ;
2005-05-26 12:55:34 +00:00
if ( ! cl . validsequence )
2004-09-30 22:40:24 +00:00
return NULL ;
2005-06-04 04:20:20 +00:00
pack = & cl . frames [ ( cls . netchan . incoming_sequence - 1 ) & UPDATE_MASK ] . packet_entities ;
2004-08-23 00:15:46 +00:00
for ( pnum = 0 ; pnum < pack - > num_entities ; pnum + + )
{
s1 = & pack - > entities [ pnum ] ;
if ( num = = s1 - > number )
return s1 ;
}
return NULL ;
}
2004-11-29 01:21:00 +00:00
# ifdef NQPROT
2004-11-27 08:16:25 +00:00
// reset all entity fields (typically used if status changed)
# define E5_FULLUPDATE (1<<0)
// E5_ORIGIN32=0: short[3] = s->origin[0] * 8, s->origin[1] * 8, s->origin[2] * 8
// E5_ORIGIN32=1: float[3] = s->origin[0], s->origin[1], s->origin[2]
# define E5_ORIGIN (1<<1)
// E5_ANGLES16=0: byte[3] = s->angle[0] * 256 / 360, s->angle[1] * 256 / 360, s->angle[2] * 256 / 360
// E5_ANGLES16=1: short[3] = s->angle[0] * 65536 / 360, s->angle[1] * 65536 / 360, s->angle[2] * 65536 / 360
# define E5_ANGLES (1<<2)
// E5_MODEL16=0: byte = s->modelindex
// E5_MODEL16=1: short = s->modelindex
# define E5_MODEL (1<<3)
// E5_FRAME16=0: byte = s->frame
// E5_FRAME16=1: short = s->frame
# define E5_FRAME (1<<4)
// byte = s->skin
# define E5_SKIN (1<<5)
// E5_EFFECTS16=0 && E5_EFFECTS32=0: byte = s->effects
// E5_EFFECTS16=1 && E5_EFFECTS32=0: short = s->effects
// E5_EFFECTS16=0 && E5_EFFECTS32=1: int = s->effects
// E5_EFFECTS16=1 && E5_EFFECTS32=1: int = s->effects
# define E5_EFFECTS (1<<6)
// bits >= (1<<8)
# define E5_EXTEND1 (1<<7)
// byte = s->renderflags
# define E5_FLAGS (1<<8)
// byte = bound(0, s->alpha * 255, 255)
# define E5_ALPHA (1<<9)
// byte = bound(0, s->scale * 16, 255)
# define E5_SCALE (1<<10)
// flag
2005-02-06 02:47:36 +00:00
# define E5_ORIGIN32 (1<<11)
2004-11-27 08:16:25 +00:00
// flag
# define E5_ANGLES16 (1<<12)
// flag
# define E5_MODEL16 (1<<13)
// byte = s->colormap
# define E5_COLORMAP (1<<14)
// bits >= (1<<16)
# define E5_EXTEND2 (1<<15)
// short = s->tagentity
// byte = s->tagindex
# define E5_ATTACHMENT (1<<16)
// short[4] = s->light[0], s->light[1], s->light[2], s->light[3]
// byte = s->lightstyle
// byte = s->lightpflags
# define E5_LIGHT (1<<17)
// byte = s->glowsize
// byte = s->glowcolor
# define E5_GLOW (1<<18)
// short = s->effects
# define E5_EFFECTS16 (1<<19)
// int = s->effects
# define E5_EFFECTS32 (1<<20)
// flag
# define E5_FRAME16 (1<<21)
// unused
2005-09-26 03:40:09 +00:00
# define E5_COLORMOD (1<<22)
2004-11-27 08:16:25 +00:00
// bits >= (1<<24)
# define E5_EXTEND3 (1<<23)
// unused
# define E5_UNUSED24 (1<<24)
// unused
# define E5_UNUSED25 (1<<25)
// unused
# define E5_UNUSED26 (1<<26)
// unused
# define E5_UNUSED27 (1<<27)
// unused
# define E5_UNUSED28 (1<<28)
// unused
# define E5_UNUSED29 (1<<29)
// unused
# define E5_UNUSED30 (1<<30)
// bits2 > 0
# define E5_EXTEND4 (1<<31)
2005-09-26 03:40:09 +00:00
# define E5_ALLUNUSED (E5_UNUSED24|E5_UNUSED25|E5_UNUSED26|E5_UNUSED27|E5_UNUSED28|E5_UNUSED29|E5_UNUSED30)
2005-07-14 01:57:34 +00:00
entity_state_t defaultstate ;
2004-11-27 08:16:25 +00:00
void DP5_ParseDelta ( entity_state_t * s )
{
int bits ;
bits = MSG_ReadByte ( ) ;
if ( bits & E5_EXTEND1 )
{
bits | = MSG_ReadByte ( ) < < 8 ;
if ( bits & E5_EXTEND2 )
{
bits | = MSG_ReadByte ( ) < < 16 ;
if ( bits & E5_EXTEND3 )
bits | = MSG_ReadByte ( ) < < 24 ;
}
}
2005-09-26 03:40:09 +00:00
if ( bits & E5_ALLUNUSED )
{
Host_EndGame ( " Detected 'unused' bits in DP5+ entity delta - %x (%x) \n " , bits , ( bits & E5_ALLUNUSED ) ) ;
}
2004-11-27 08:16:25 +00:00
if ( bits & E5_FULLUPDATE )
{
2005-05-15 18:49:04 +00:00
int num ;
num = s - > number ;
2004-11-27 08:16:25 +00:00
* s = defaultstate ;
2005-07-14 01:57:34 +00:00
s - > trans = 255 ;
2005-08-26 22:56:51 +00:00
s - > scale = 16 ;
2005-05-15 18:49:04 +00:00
s - > number = num ;
2004-11-27 08:16:25 +00:00
// s->active = true;
}
if ( bits & E5_FLAGS )
2005-05-17 02:36:54 +00:00
{
int i = MSG_ReadByte ( ) ;
s - > flags = 0 ;
if ( i & 4 )
s - > flags | = Q2RF_WEAPONMODEL | Q2RF_MINLIGHT | Q2RF_DEPTHHACK ;
if ( i & 8 )
s - > flags | = Q2RF_EXTERNALMODEL ;
}
2004-11-27 08:16:25 +00:00
if ( bits & E5_ORIGIN )
{
if ( bits & E5_ORIGIN32 )
{
s - > origin [ 0 ] = MSG_ReadFloat ( ) ;
s - > origin [ 1 ] = MSG_ReadFloat ( ) ;
s - > origin [ 2 ] = MSG_ReadFloat ( ) ;
}
else
{
s - > origin [ 0 ] = MSG_ReadShort ( ) * ( 1 / 8.0f ) ;
s - > origin [ 1 ] = MSG_ReadShort ( ) * ( 1 / 8.0f ) ;
s - > origin [ 2 ] = MSG_ReadShort ( ) * ( 1 / 8.0f ) ;
}
}
if ( bits & E5_ANGLES )
{
if ( bits & E5_ANGLES16 )
{
2005-02-06 02:47:36 +00:00
s - > angles [ 0 ] = MSG_ReadAngle16 ( ) ;
s - > angles [ 1 ] = MSG_ReadAngle16 ( ) ;
s - > angles [ 2 ] = MSG_ReadAngle16 ( ) ;
2004-11-27 08:16:25 +00:00
}
else
{
s - > angles [ 0 ] = MSG_ReadChar ( ) * ( 360.0 / 256 ) ;
s - > angles [ 1 ] = MSG_ReadChar ( ) * ( 360.0 / 256 ) ;
s - > angles [ 2 ] = MSG_ReadChar ( ) * ( 360.0 / 256 ) ;
}
}
if ( bits & E5_MODEL )
{
if ( bits & E5_MODEL16 )
s - > modelindex = ( unsigned short ) MSG_ReadShort ( ) ;
else
s - > modelindex = MSG_ReadByte ( ) ;
}
if ( bits & E5_FRAME )
{
if ( bits & E5_FRAME16 )
s - > frame = ( unsigned short ) MSG_ReadShort ( ) ;
else
s - > frame = MSG_ReadByte ( ) ;
}
if ( bits & E5_SKIN )
s - > skinnum = MSG_ReadByte ( ) ;
if ( bits & E5_EFFECTS )
{
if ( bits & E5_EFFECTS32 )
s - > effects = ( unsigned int ) MSG_ReadLong ( ) ;
else if ( bits & E5_EFFECTS16 )
s - > effects = ( unsigned short ) MSG_ReadShort ( ) ;
else
s - > effects = MSG_ReadByte ( ) ;
}
if ( bits & E5_ALPHA )
2005-07-01 19:23:00 +00:00
s - > trans = MSG_ReadByte ( ) ;
2004-11-27 08:16:25 +00:00
if ( bits & E5_SCALE )
2005-07-01 19:23:00 +00:00
s - > scale = MSG_ReadByte ( ) ;
2004-11-27 08:16:25 +00:00
if ( bits & E5_COLORMAP )
s - > colormap = MSG_ReadByte ( ) ;
if ( bits & E5_ATTACHMENT )
{
2005-07-01 19:23:00 +00:00
s - > tagentity = MSG_ReadShort ( ) ;
s - > tagindex = MSG_ReadByte ( ) ;
2004-11-27 08:16:25 +00:00
}
if ( bits & E5_LIGHT )
{
2005-09-26 03:40:09 +00:00
s - > light [ 0 ] = MSG_ReadShort ( ) ;
s - > light [ 1 ] = MSG_ReadShort ( ) ;
s - > light [ 2 ] = MSG_ReadShort ( ) ;
s - > light [ 3 ] = MSG_ReadShort ( ) ;
s - > lightstyle = MSG_ReadByte ( ) ;
s - > lightpflags = MSG_ReadByte ( ) ;
2004-11-27 08:16:25 +00:00
}
if ( bits & E5_GLOW )
{
2005-05-19 02:53:03 +00:00
s - > glowsize = MSG_ReadByte ( ) ;
s - > glowcolour = MSG_ReadByte ( ) ;
2004-11-27 08:16:25 +00:00
}
2005-09-26 03:40:09 +00:00
if ( bits & E5_COLORMOD )
{
MSG_ReadByte ( ) ;
MSG_ReadByte ( ) ;
MSG_ReadByte ( ) ;
}
2004-11-27 08:16:25 +00:00
}
int cl_latestframenum ;
void CLNQ_ParseDarkPlaces5Entities ( void ) //the things I do.. :o(
{
//the incoming entities do not come in in any order. :(
//well, they come in in order of priorities, but that's not useful to us.
//I guess this means we'll have to go slowly.
packet_entities_t * pack , * oldpack ;
2005-02-06 02:47:36 +00:00
entity_state_t * to , * from ;
2004-11-27 08:16:25 +00:00
unsigned short read ;
int oldi ;
qboolean remove ;
cl_latestframenum = MSG_ReadLong ( ) ;
2005-05-26 12:55:34 +00:00
if ( nq_dp_protocol > = 7 )
/*cl.servermovesequence =*/ MSG_ReadLong ( ) ;
2004-11-27 08:16:25 +00:00
pack = & cl . frames [ ( cls . netchan . incoming_sequence ) & UPDATE_MASK ] . packet_entities ;
2005-11-26 03:02:55 +00:00
pack - > servertime = cl . gametime ;
2004-11-27 08:16:25 +00:00
oldpack = & cl . frames [ ( cls . netchan . incoming_sequence - 1 ) & UPDATE_MASK ] . packet_entities ;
from = oldpack - > entities ;
oldi = 0 ;
pack - > num_entities = 0 ;
for ( oldi = 0 ; oldi < oldpack - > num_entities ; oldi + + )
{
from = & oldpack - > entities [ oldi ] ;
from - > flags & = ~ 0x80000000 ;
}
for ( read = MSG_ReadShort ( ) ; read ! = 0x8000 ; read = MSG_ReadShort ( ) )
{
if ( msg_badread )
Host_EndGame ( " Corrupt entitiy message packet \n " ) ;
remove = ! ! ( read & 0x8000 ) ;
read & = ~ 0x8000 ;
2005-08-26 22:56:51 +00:00
if ( read > = MAX_EDICTS )
Host_EndGame ( " Too many entities. \n " ) ;
2004-11-27 08:16:25 +00:00
from = & defaultstate ;
for ( oldi = 0 ; oldi < oldpack - > num_entities ; oldi + + )
{
if ( read = = oldpack - > entities [ oldi ] . number )
{
from = & oldpack - > entities [ oldi ] ;
2005-05-19 02:53:03 +00:00
from - > flags | = 0x80000000 ; //so we don't copy it.
2004-11-27 08:16:25 +00:00
break ;
}
}
if ( remove )
{
continue ;
}
if ( pack - > num_entities = = pack - > max_entities )
{
pack - > max_entities = pack - > num_entities + 16 ;
pack - > entities = BZ_Realloc ( pack - > entities , sizeof ( entity_state_t ) * pack - > max_entities ) ;
}
to = & pack - > entities [ pack - > num_entities ] ;
pack - > num_entities + + ;
memcpy ( to , from , sizeof ( * to ) ) ;
to - > number = read ;
2005-05-15 18:49:04 +00:00
DP5_ParseDelta ( to ) ;
2005-05-19 02:53:03 +00:00
to - > flags & = ~ 0x80000000 ;
2004-11-27 08:16:25 +00:00
}
//the pack has all the new ones in it, now copy the old ones in that wern't removed (or changed).
for ( oldi = 0 ; oldi < oldpack - > num_entities ; oldi + + )
{
from = & oldpack - > entities [ oldi ] ;
if ( from - > flags & 0x80000000 )
continue ;
if ( pack - > num_entities = = pack - > max_entities )
{
pack - > max_entities = pack - > num_entities + 16 ;
pack - > entities = BZ_Realloc ( pack - > entities , sizeof ( entity_state_t ) * pack - > max_entities ) ;
}
to = & pack - > entities [ pack - > num_entities ] ;
pack - > num_entities + + ;
from = & oldpack - > entities [ oldi ] ;
memcpy ( to , from , sizeof ( * to ) ) ;
}
}
2004-08-23 00:15:46 +00:00
2004-11-23 01:10:10 +00:00
void CLNQ_ParseEntity ( unsigned int bits )
2004-08-23 00:15:46 +00:00
{
int i ;
int num , pnum ;
2005-02-06 02:47:36 +00:00
entity_state_t * state , * from ;
2004-08-23 00:15:46 +00:00
entity_state_t * base ;
static float lasttime ;
packet_entities_t * pack ;
2004-11-23 01:10:10 +00:00
2004-08-23 00:15:46 +00:00
# define NQU_MOREBITS (1<<0)
# define NQU_ORIGIN1 (1<<1)
# define NQU_ORIGIN2 (1<<2)
# define NQU_ORIGIN3 (1<<3)
# define NQU_ANGLE2 (1<<4)
# define NQU_NOLERP (1<<5) // don't interpolate movement
# define NQU_FRAME (1<<6)
# define NQU_SIGNAL (1<<7) // just differentiates from other updates
// svc_update can pass all of the fast update bits, plus more
# define NQU_ANGLE1 (1<<8)
# define NQU_ANGLE3 (1<<9)
# define NQU_MODEL (1<<10)
# define NQU_COLORMAP (1<<11)
# define NQU_SKIN (1<<12)
# define NQU_EFFECTS (1<<13)
# define NQU_LONGENTITY (1<<14)
2005-02-06 02:47:36 +00:00
2004-11-23 01:10:10 +00:00
// LordHavoc's: protocol extension
# define DPU_EXTEND1 (1<<15)
// LordHavoc: first extend byte
# define DPU_DELTA (1<<16) // no data, while this is set the entity is delta compressed (uses previous frame as a baseline, meaning only things that have changed from the previous frame are sent, except for the forced full update every half second)
# define DPU_ALPHA (1<<17) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 1, and the entity is not sent if <=0 unless it has effects (model effects are checked as well)
# define DPU_SCALE (1<<18) // 1 byte, scale / 16 positive, not sent if 1.0
# define DPU_EFFECTS2 (1<<19) // 1 byte, this is .effects & 0xFF00 (second byte)
# define DPU_GLOWSIZE (1<<20) // 1 byte, encoding is float/4.0, unsigned, not sent if 0
# define DPU_GLOWCOLOR (1<<21) // 1 byte, palette index, default is 254 (white), this IS used for darklight (allowing colored darklight), however the particles from a darklight are always black, not sent if default value (even if glowsize or glowtrail is set)
// LordHavoc: colormod feature has been removed, because no one used it
# define DPU_COLORMOD (1<<22) // 1 byte, 3 bit red, 3 bit green, 2 bit blue, this lets you tint an object artifically, so you could make a red rocket, or a blue fiend...
# define DPU_EXTEND2 (1<<23) // another byte to follow
// LordHavoc: second extend byte
# define DPU_GLOWTRAIL (1<<24) // leaves a trail of particles (of color .glowcolor, or black if it is a negative glowsize)
# define DPU_VIEWMODEL (1<<25) // attachs the model to the view (origin and angles become relative to it), only shown to owner, a more powerful alternative to .weaponmodel and such
# define DPU_FRAME2 (1<<26) // 1 byte, this is .frame & 0xFF00 (second byte)
# define DPU_MODEL2 (1<<27) // 1 byte, this is .modelindex & 0xFF00 (second byte)
# define DPU_EXTERIORMODEL (1<<28) // causes this model to not be drawn when using a first person view (third person will draw it, first person will not)
# define DPU_UNUSED29 (1<<29) // future expansion
# define DPU_UNUSED30 (1<<30) // future expansion
# define DPU_EXTEND3 (1<<31) // another byte to follow, future expansion
2004-08-23 00:15:46 +00:00
if ( cls . signon = = 4 - 1 )
{ // first update is the final signon stage
cls . signon = 4 ;
CLNQ_SignonReply ( ) ;
2005-02-06 02:47:36 +00:00
}
pack = & cl . frames [ cls . netchan . incoming_sequence & UPDATE_MASK ] . packet_entities ;
2004-08-23 00:15:46 +00:00
if ( bits & NQU_MOREBITS )
{
i = MSG_ReadByte ( ) ;
bits | = ( i < < 8 ) ;
}
2004-11-23 01:10:10 +00:00
if ( bits & DPU_EXTEND1 )
{
i = MSG_ReadByte ( ) ;
bits | = ( i < < 16 ) ;
}
if ( bits & DPU_EXTEND2 )
{
i = MSG_ReadByte ( ) ;
bits | = ( i < < 24 ) ;
}
2004-08-23 00:15:46 +00:00
2005-02-06 02:47:36 +00:00
if ( bits & NQU_LONGENTITY )
2004-08-23 00:15:46 +00:00
num = MSG_ReadShort ( ) ;
else
num = MSG_ReadByte ( ) ;
// state = CL_FindPacketEntity(num);
// if (!state)
{
// if ((int)(lasttime*100) != (int)(realtime*100))
// pack->num_entities=0;
// else
if ( pack - > num_entities = = pack - > max_entities )
{
pack - > max_entities = pack - > num_entities + 1 ;
pack - > entities = BZ_Realloc ( pack - > entities , sizeof ( entity_state_t ) * pack - > max_entities ) ;
}
lasttime = realtime ;
state = & pack - > entities [ pack - > num_entities + + ] ;
}
2004-11-27 08:16:25 +00:00
from = CL_FindOldPacketEntity ( num ) ; //this could be optimised.
2004-08-23 00:15:46 +00:00
base = & cl_baselines [ num ] ;
state - > number = num ;
2005-02-06 02:47:36 +00:00
if ( bits & NQU_MODEL )
2004-08-23 00:15:46 +00:00
state - > modelindex = MSG_ReadByte ( ) ;
else
state - > modelindex = base - > modelindex ;
if ( bits & NQU_FRAME )
state - > frame = MSG_ReadByte ( ) ;
else
state - > frame = base - > frame ;
if ( bits & NQU_COLORMAP )
state - > colormap = MSG_ReadByte ( ) ;
else
state - > colormap = 0 ;
if ( bits & NQU_SKIN )
state - > skinnum = MSG_ReadByte ( ) ;
else
state - > skinnum = base - > skinnum ;
if ( bits & NQU_EFFECTS )
state - > effects = MSG_ReadByte ( ) ;
else
state - > effects = base - > effects ;
if ( bits & NQU_ORIGIN1 )
state - > origin [ 0 ] = MSG_ReadCoord ( ) ;
else
state - > origin [ 0 ] = base - > origin [ 0 ] ;
if ( bits & NQU_ANGLE1 )
state - > angles [ 0 ] = MSG_ReadAngle ( ) ;
else
state - > angles [ 0 ] = base - > angles [ 0 ] ;
if ( bits & NQU_ORIGIN2 )
state - > origin [ 1 ] = MSG_ReadCoord ( ) ;
else
state - > origin [ 1 ] = base - > origin [ 1 ] ;
if ( bits & NQU_ANGLE2 )
state - > angles [ 1 ] = MSG_ReadAngle ( ) ;
else
state - > angles [ 1 ] = base - > angles [ 1 ] ;
if ( bits & NQU_ORIGIN3 )
state - > origin [ 2 ] = MSG_ReadCoord ( ) ;
else
state - > origin [ 2 ] = base - > origin [ 2 ] ;
if ( bits & NQU_ANGLE3 )
state - > angles [ 2 ] = MSG_ReadAngle ( ) ;
else
state - > angles [ 2 ] = base - > angles [ 2 ] ;
2005-08-12 01:37:27 +00:00
# ifdef PEXT_SCALE
state - > scale = 1 * 16 ;
# endif
# ifdef PEXT_TRANS
state - > trans = 255 ;
# endif
2004-08-23 00:15:46 +00:00
if ( cls . demoplayback ! = DPB_NONE )
for ( pnum = 0 ; pnum < cl . splitclients ; pnum + + )
if ( num = = cl . viewentity [ pnum ] )
{
state - > angles [ 0 ] = cl . viewangles [ pnum ] [ 0 ] / - 3 ;
state - > angles [ 1 ] = cl . viewangles [ pnum ] [ 1 ] ;
state - > angles [ 2 ] = cl . viewangles [ pnum ] [ 2 ] ;
}
}
# endif
# ifdef PEXT_SETVIEW
entity_state_t * CL_FindPacketEntity ( int num )
{
int pnum ;
entity_state_t * s1 ;
packet_entities_t * pack ;
pack = & cl . frames [ cls . netchan . incoming_sequence & UPDATE_MASK ] . packet_entities ;
for ( pnum = 0 ; pnum < pack - > num_entities ; pnum + + )
{
s1 = & pack - > entities [ pnum ] ;
if ( num = = s1 - > number )
return s1 ;
}
return NULL ;
}
# endif
2005-02-28 07:16:19 +00:00
//return 0 to 1
//1 being entirly new frame.
float CL_LerpEntityFrac ( float lerprate , float lerptime )
{
float f ;
if ( ! lerprate )
{
return 0 ;
}
else
{
f = 1 - ( cl . time - lerptime ) / lerprate ;
}
if ( f < 0 ) f = 0 ;
if ( f > 1 ) f = 1 ;
return f ;
}
2005-06-14 04:52:10 +00:00
float CL_EntLerpFactor ( int entnum )
{
float f ;
if ( cl . lerpents [ entnum ] . lerprate < = 0 )
return 0 ;
else
f = 1 - ( cl . time - cl . lerpents [ entnum ] . lerptime ) / cl . lerpents [ entnum ] . lerprate ;
if ( f < 0 )
f = 0 ;
if ( f > 1 )
f = 1 ;
return f ;
}
2005-02-06 02:47:36 +00:00
void CL_RotateAroundTag ( entity_t * ent , int num , int tagent , int tagnum )
2004-10-10 06:32:29 +00:00
{
entity_state_t * ps ;
float * org = NULL , * ang = NULL ;
2004-11-17 17:55:19 +00:00
vec3_t axis [ 3 ] ;
2005-06-14 04:52:10 +00:00
float transform [ 12 ] , parent [ 12 ] , result [ 12 ] , old [ 12 ] , temp [ 12 ] ;
2004-11-17 17:55:19 +00:00
2004-11-23 01:10:10 +00:00
int model = 0 ; //these two are only initialised because msvc sucks at detecting usage.
int frame = 0 ;
2005-06-14 04:52:10 +00:00
int frame2 = cl . lerpents [ tagent ] . frame ;
float frame2ness ;
2004-10-10 06:32:29 +00:00
2005-02-28 07:16:19 +00:00
ent - > keynum = tagent ;
2004-11-17 17:55:19 +00:00
ps = CL_FindPacketEntity ( tagent ) ;
2004-10-10 06:32:29 +00:00
if ( ps )
{
2005-07-01 19:23:00 +00:00
if ( ps - > tagentity )
CL_RotateAroundTag ( ent , num , ps - > tagentity , ps - > tagindex ) ;
2004-10-10 06:32:29 +00:00
org = ps - > origin ;
ang = ps - > angles ;
2004-11-17 17:55:19 +00:00
model = ps - > modelindex ;
frame = ps - > frame ;
2004-10-10 06:32:29 +00:00
}
else
{
extern int parsecountmod ;
2005-02-06 02:47:36 +00:00
// Con_Printf("tagent %i\n", tagent);
2004-11-17 17:55:19 +00:00
if ( tagent < = MAX_CLIENTS & & tagent > 0 )
2004-10-10 06:32:29 +00:00
{
2004-11-17 17:55:19 +00:00
if ( tagent - 1 = = cl . playernum [ 0 ] )
2004-10-10 06:32:29 +00:00
{
org = cl . simorg [ 0 ] ;
ang = cl . simangles [ 0 ] ;
}
else
{
2004-11-17 17:55:19 +00:00
org = cl . frames [ parsecountmod ] . playerstate [ tagent - 1 ] . origin ;
ang = cl . frames [ parsecountmod ] . playerstate [ tagent - 1 ] . viewangles ;
2004-10-10 06:32:29 +00:00
}
2004-11-17 17:55:19 +00:00
model = cl . frames [ parsecountmod ] . playerstate [ tagent - 1 ] . modelindex ;
frame = cl . frames [ parsecountmod ] . playerstate [ tagent - 1 ] . frame ;
2004-10-10 06:32:29 +00:00
}
}
if ( ang )
{
2004-11-17 17:55:19 +00:00
AngleVectors ( ang , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
VectorInverse ( axis [ 1 ] ) ;
2005-06-14 04:52:10 +00:00
frame2ness = CL_EntLerpFactor ( tagent ) ;
2005-07-01 19:23:00 +00:00
if ( Mod_GetTag & & Mod_GetTag ( cl . model_precache [ model ] , tagnum , frame , frame2 , frame2ness , cl . time - cl . lerpents [ tagent ] . framechange , cl . time - cl . lerpents [ tagent ] . oldframechange , transform ) )
2004-11-17 17:55:19 +00:00
{
2005-06-14 04:52:10 +00:00
old [ 0 ] = ent - > axis [ 0 ] [ 0 ] ;
old [ 1 ] = ent - > axis [ 1 ] [ 0 ] ;
old [ 2 ] = ent - > axis [ 2 ] [ 0 ] ;
old [ 3 ] = ent - > origin [ 0 ] ;
old [ 4 ] = ent - > axis [ 0 ] [ 1 ] ;
old [ 5 ] = ent - > axis [ 1 ] [ 1 ] ;
old [ 6 ] = ent - > axis [ 2 ] [ 1 ] ;
old [ 7 ] = ent - > origin [ 1 ] ;
old [ 8 ] = ent - > axis [ 0 ] [ 2 ] ;
old [ 9 ] = ent - > axis [ 1 ] [ 2 ] ;
old [ 10 ] = ent - > axis [ 2 ] [ 2 ] ;
old [ 11 ] = ent - > origin [ 2 ] ;
parent [ 0 ] = axis [ 0 ] [ 0 ] ;
parent [ 1 ] = axis [ 1 ] [ 0 ] ;
parent [ 2 ] = axis [ 2 ] [ 0 ] ;
parent [ 3 ] = org [ 0 ] ;
parent [ 4 ] = axis [ 0 ] [ 1 ] ;
parent [ 5 ] = axis [ 1 ] [ 1 ] ;
parent [ 6 ] = axis [ 2 ] [ 1 ] ;
parent [ 7 ] = org [ 1 ] ;
parent [ 8 ] = axis [ 0 ] [ 2 ] ;
parent [ 9 ] = axis [ 1 ] [ 2 ] ;
parent [ 10 ] = axis [ 2 ] [ 2 ] ;
parent [ 11 ] = org [ 2 ] ;
R_ConcatTransforms ( ( void * ) old , ( void * ) parent , ( void * ) temp ) ;
R_ConcatTransforms ( ( void * ) temp , ( void * ) transform , ( void * ) result ) ;
ent - > axis [ 0 ] [ 0 ] = result [ 0 ] ;
ent - > axis [ 1 ] [ 0 ] = result [ 1 ] ;
ent - > axis [ 2 ] [ 0 ] = result [ 2 ] ;
ent - > origin [ 0 ] = result [ 3 ] ;
ent - > axis [ 0 ] [ 1 ] = result [ 4 ] ;
ent - > axis [ 1 ] [ 1 ] = result [ 5 ] ;
ent - > axis [ 2 ] [ 1 ] = result [ 6 ] ;
ent - > origin [ 1 ] = result [ 7 ] ;
ent - > axis [ 0 ] [ 2 ] = result [ 8 ] ;
ent - > axis [ 1 ] [ 2 ] = result [ 9 ] ;
ent - > axis [ 2 ] [ 2 ] = result [ 10 ] ;
ent - > origin [ 2 ] = result [ 11 ] ;
2004-11-17 17:55:19 +00:00
}
else //hrm.
2005-02-06 02:47:36 +00:00
{
2005-05-15 18:49:04 +00:00
memcpy ( ent - > axis , axis , sizeof ( temp ) ) ;
VectorCopy ( org , ent - > origin ) ;
2005-02-06 02:47:36 +00:00
}
2004-10-10 06:32:29 +00:00
}
}
2005-02-28 07:16:19 +00:00
2005-08-03 23:14:59 +00:00
void V_AddAxisEntity ( entity_t * in )
{
entity_t * ent ;
if ( cl_numvisedicts = = MAX_VISEDICTS )
{
Con_Printf ( " Visedict list is full! \n " ) ;
return ; // object list is full
}
ent = & cl_visedicts [ cl_numvisedicts ] ;
cl_numvisedicts + + ;
* ent = * in ;
}
2005-02-28 07:16:19 +00:00
void V_AddEntity ( entity_t * in )
{
entity_t * ent ;
2005-06-04 04:20:20 +00:00
2005-02-28 07:16:19 +00:00
if ( cl_numvisedicts = = MAX_VISEDICTS )
2005-06-04 04:20:20 +00:00
{
Con_Printf ( " Visedict list is full! \n " ) ;
2005-02-28 07:16:19 +00:00
return ; // object list is full
2005-06-04 04:20:20 +00:00
}
2005-02-28 07:16:19 +00:00
ent = & cl_visedicts [ cl_numvisedicts ] ;
cl_numvisedicts + + ;
* ent = * in ;
ent - > angles [ 0 ] * = - 1 ;
AngleVectors ( ent - > angles , ent - > axis [ 0 ] , ent - > axis [ 1 ] , ent - > axis [ 2 ] ) ;
VectorInverse ( ent - > axis [ 1 ] ) ;
ent - > angles [ 0 ] * = - 1 ;
}
2005-03-18 06:14:07 +00:00
void V_AddLerpEntity ( entity_t * in ) //a convienience function
{
entity_t * ent ;
float fwds , back ;
int i ;
if ( cl_numvisedicts = = MAX_VISEDICTS )
return ; // object list is full
ent = & cl_visedicts [ cl_numvisedicts ] ;
cl_numvisedicts + + ;
* ent = * in ;
fwds = ent - > lerpfrac ;
back = 1 - ent - > lerpfrac ;
for ( i = 0 ; i < 3 ; i + + )
{
ent - > origin [ i ] = in - > origin [ i ] * fwds + in - > oldorigin [ i ] * back ;
}
2005-05-15 18:49:04 +00:00
ent - > lerpfrac = 1 - ent - > lerpfrac ;
2005-03-18 06:14:07 +00:00
ent - > angles [ 0 ] * = - 1 ;
AngleVectors ( ent - > angles , ent - > axis [ 0 ] , ent - > axis [ 1 ] , ent - > axis [ 2 ] ) ;
VectorInverse ( ent - > axis [ 1 ] ) ;
ent - > angles [ 0 ] * = - 1 ;
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = =
CL_LinkPacketEntities
= = = = = = = = = = = = = = =
*/
void R_FlameTrail ( vec3_t start , vec3_t end , float seperation ) ;
2005-11-26 03:02:55 +00:00
# define DECENTLERP
# ifdef DECENTLERP
void CL_TransitionPacketEntities ( packet_entities_t * newpack , packet_entities_t * oldpack , float servertime )
{
lerpents_t * le ;
entity_state_t * snew , * sold ;
int i , j ;
int oldpnum , newpnum ;
vec3_t move ;
float a1 , a2 ;
float frac ;
/*
seeing as how dropped packets cannot be filled in due to the reliable networking stuff ,
We can simply detect changes and lerp towards them
*/
//we have two index-sorted lists of entities
//we figure out which ones are new,
//we don't care about old, as our caller will use the lerpents array we fill, and the entity numbers from the 'new' packet.
if ( newpack - > servertime = = oldpack - > servertime )
frac = 1 ; //lerp totally into the new
else
frac = ( servertime - oldpack - > servertime ) / ( newpack - > servertime - oldpack - > servertime ) ;
oldpnum = 0 ;
for ( newpnum = 0 ; newpnum < newpack - > num_entities ; newpnum + + )
{
snew = & newpack - > entities [ newpnum ] ;
sold = NULL ;
for ( ; oldpnum < oldpack - > num_entities ; oldpnum + + )
{
sold = & oldpack - > entities [ oldpnum ] ;
if ( sold - > number > = snew - > number )
{
if ( sold - > number > snew - > number )
sold = NULL ; //woo, it's a new entity.
break ;
}
}
if ( ! sold ) //I'm lazy
sold = snew ;
if ( snew - > number > = cl . maxlerpents )
{
cl . maxlerpents = snew - > number + 16 ;
cl . lerpents = BZ_Realloc ( cl . lerpents , cl . maxlerpents * sizeof ( lerpents_t ) ) ;
}
le = & cl . lerpents [ snew - > number ] ;
VectorSubtract ( snew - > origin , sold - > origin , move )
if ( DotProduct ( move , move ) > 200 * 200 | | snew - > modelindex ! = sold - > modelindex )
{
sold = snew ; //teleported?
VectorClear ( move ) ;
}
for ( i = 0 ; i < 3 ; i + + )
{
le - > origin [ i ] = sold - > origin [ i ] + frac * ( move [ i ] ) ;
for ( j = 0 ; j < 3 ; j + + )
{
a1 = sold - > angles [ i ] ;
a2 = snew - > angles [ i ] ;
if ( a1 - a2 > 180 )
a1 - = 360 ;
if ( a1 - a2 < - 180 )
a1 + = 360 ;
le - > angles [ i ] = a1 + frac * ( a2 - a1 ) ;
}
}
if ( snew = = sold | | ( sold - > frame ! = le - > frame & & sold - > frame ! = snew - > frame ) | | snew - > modelindex ! = sold - > modelindex )
{
le - > oldframechange = le - > framechange ;
le - > framechange = newpack - > servertime ;
le - > frame = sold - > frame ;
}
}
}
packet_entities_t * CL_ProcessPacketEntities ( float * servertime , qboolean nolerp )
{
packet_entities_t * packnew , * packold ;
int i ;
static float oldoldtime ;
//, spnum;
if ( nolerp )
{ //force our emulated time to as late as we can.
//this will disable all position interpolation
* servertime = cl . frames [ cls . netchan . incoming_sequence & UPDATE_MASK ] . packet_entities . servertime ;
2006-01-02 23:01:54 +00:00
// Con_DPrintf("No lerp\n");
2005-11-26 03:02:55 +00:00
}
packnew = NULL ;
packold = NULL ;
//choose the two packets.
//we should be picking the packet just after the server time, and the one just before
for ( i = cls . netchan . incoming_sequence ; i > = cls . netchan . incoming_sequence - UPDATE_MASK ; i - - )
{
if ( cl . frames [ i & UPDATE_MASK ] . receivedtime < 0 | | cl . frames [ i & UPDATE_MASK ] . invalid )
continue ; //packetloss/choke, it's really only a problem for the oldframe, but...
if ( cl . frames [ i & UPDATE_MASK ] . packet_entities . servertime > = * servertime )
{
if ( cl . frames [ i & UPDATE_MASK ] . packet_entities . servertime )
{
if ( ! packnew | | packnew - > servertime ! = cl . frames [ i & UPDATE_MASK ] . packet_entities . servertime ) //if it's a duplicate, pick the latest (so just-shot rockets are still present)
packnew = & cl . frames [ i & UPDATE_MASK ] . packet_entities ;
}
}
else if ( packnew )
{
if ( cl . frames [ i & UPDATE_MASK ] . packet_entities . servertime ! = packnew - > servertime )
{ //it does actually lerp, and isn't an identical frame.
packold = & cl . frames [ i & UPDATE_MASK ] . packet_entities ;
break ;
}
}
}
//Note, hacking this to return anyway still needs the lerpent array to be valid for all contained entities.
if ( ! packnew ) //should never happen
{
Con_DPrintf ( " Warning: No lerp-to frame packet \n " ) ;
return NULL ;
}
if ( ! packold ) //can happem at map start, and really laggy games, but really shouldn't in a normal game
{
Con_DPrintf ( " Warning: No lerp-from frame packet \n " ) ;
packold = packnew ;
}
CL_TransitionPacketEntities ( packnew , packold , * servertime ) ;
2006-01-02 23:01:54 +00:00
// Con_DPrintf("%f %f %f %f %f %f\n", packnew->servertime, *servertime, packold->servertime, cl.gametime, cl.oldgametime, cl.servertime);
2005-11-26 03:02:55 +00:00
// if (packold->servertime < oldoldtime)
// Con_Printf("Spike screwed up\n");
// oldoldtime = packold->servertime;
return packnew ;
}
void CL_LinkPacketEntities ( void )
{
entity_t * ent ;
packet_entities_t * pack ;
entity_state_t * state ;
lerpents_t * le ;
model_t * model ;
vec3_t old_origin ;
float autorotate ;
int i ;
2005-11-30 01:20:53 +00:00
int newpnum ;
2005-11-26 03:02:55 +00:00
//, spnum;
dlight_t * dl ;
vec3_t angles ;
int flicker ;
float servertime ;
CL_CalcClientTime ( ) ;
servertime = cl . servertime ;
pack = CL_ProcessPacketEntities ( & servertime , ! ! cl_nolerp . value ) ;
if ( ! pack )
return ;
servertime = cl . servertime ;
autorotate = anglemod ( 100 * servertime ) ;
for ( newpnum = 0 ; newpnum < pack - > num_entities ; newpnum + + )
{
state = & pack - > entities [ newpnum ] ;
if ( cl_numvisedicts = = MAX_VISEDICTS )
{
Con_Printf ( " Too many visible entities \n " ) ;
break ;
}
ent = & cl_visedicts [ cl_numvisedicts ] ;
# ifdef Q3SHADERS
ent - > forcedshader = NULL ;
# endif
le = & cl . lerpents [ state - > number ] ;
if ( le - > framechange = = le - > oldframechange )
ent - > lerpfrac = 0 ;
else
{
ent - > lerpfrac = 1 - ( servertime - le - > oldframechange ) / ( le - > framechange - le - > oldframechange ) ;
}
VectorCopy ( le - > origin , ent - > origin )
//bots or powerup glows. Bots always glow, powerups can be disabled
if ( state - > modelindex ! = cl_playerindex & & r_powerupglow . value ) ;
{
flicker = r_lightflicker . value ? ( rand ( ) & 31 ) : 0 ;
// spawn light flashes, even ones coming from invisible objects
if ( ( state - > effects & ( EF_BLUE | EF_RED ) ) = = ( EF_BLUE | EF_RED ) )
CL_NewDlight ( state - > number , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + flicker , 0 , 3 ) ;
else if ( state - > effects & EF_BLUE )
CL_NewDlight ( state - > number , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + flicker , 0 , 1 ) ;
else if ( state - > effects & EF_RED )
CL_NewDlight ( state - > number , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + flicker , 0 , 2 ) ;
else if ( state - > effects & EF_BRIGHTLIGHT )
CL_NewDlight ( state - > number , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] + 16 , 400 + flicker , 0 , 0 ) ;
else if ( state - > effects & EF_DIMLIGHT )
CL_NewDlight ( state - > number , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + flicker , 0 , 0 ) ;
}
if ( state - > light [ 3 ] )
{
CL_NewDlightRGB ( state - > number , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , state - > light [ 3 ] , 0 , state - > light [ 0 ] / 1024.0f , state - > light [ 1 ] / 1024.0f , state - > light [ 2 ] / 1024.0f ) ;
}
// if set to invisible, skip
if ( state - > modelindex < 1 )
continue ;
// create a new entity
if ( cl_numvisedicts = = MAX_VISEDICTS )
break ; // object list is full
if ( CL_FilterModelindex ( state - > modelindex , state - > frame ) )
continue ;
model = cl . model_precache [ state - > modelindex ] ;
if ( ! model )
{
Con_DPrintf ( " Bad modelindex (%i) \n " , state - > modelindex ) ;
continue ;
}
cl_numvisedicts + + ;
# ifdef Q3SHADERS
ent - > forcedshader = NULL ;
# endif
ent - > visframe = 0 ;
ent - > keynum = state - > number ;
if ( cl_r2g . value & & state - > modelindex = = cl_rocketindex & & cl_rocketindex & & cl_grenadeindex )
ent - > model = cl . model_precache [ cl_grenadeindex ] ;
else
ent - > model = model ;
ent - > flags = state - > flags ;
if ( state - > effects & NQEF_ADDATIVE )
ent - > flags | = Q2RF_ADDATIVE ;
if ( state - > effects & EF_NODEPTHTEST )
ent - > flags | = RF_NODEPTHTEST ;
// set colormap
if ( state - > colormap & & ( state - > colormap < = MAX_CLIENTS )
& & ( gl_nocolors . value = = - 1 | | ( ent - > model /* && state->modelindex == cl_playerindex*/ ) ) )
{
2005-12-22 20:35:04 +00:00
// TODO: DP colormap/colormod extension?
2005-12-22 21:46:28 +00:00
# ifdef SWQUAKE
2005-12-22 20:35:04 +00:00
ent - > palremap = cl . players [ state - > colormap - 1 ] . palremap ;
2005-12-22 21:46:28 +00:00
# endif
2005-11-26 03:02:55 +00:00
ent - > scoreboard = & cl . players [ state - > colormap - 1 ] ;
}
else
{
2005-12-22 21:46:28 +00:00
# ifdef SWQUAKE
2005-12-22 20:35:04 +00:00
ent - > palremap = D_IdentityRemap ( ) ;
2005-12-22 21:46:28 +00:00
# endif
2005-11-26 03:02:55 +00:00
ent - > scoreboard = NULL ;
}
// set skin
ent - > skinnum = state - > skinnum ;
ent - > abslight = state - > abslight ;
ent - > drawflags = state - > hexen2flags ;
// set frame
ent - > frame = state - > frame ;
ent - > oldframe = le - > frame ;
ent - > frame1time = cl . servertime - le - > framechange ;
ent - > frame2time = cl . servertime - le - > oldframechange ;
// f = (sin(realtime)+1)/2;
# ifdef PEXT_SCALE
//set scale
ent - > scale = state - > scale / 16.0 ;
# endif
# ifdef PEXT_TRANS
//set trans
ent - > alpha = state - > trans / 255.0 ;
# endif
# ifdef PEXT_FATNESS
//set trans
ent - > fatness = state - > fatness / 2.0 ;
# endif
// rotate binary objects locally
if ( model & & model - > flags & EF_ROTATE )
{
angles [ 0 ] = 0 ;
angles [ 1 ] = autorotate ;
angles [ 2 ] = 0 ;
if ( cl_item_bobbing . value )
ent - > origin [ 2 ] + = 5 + sin ( cl . time * 3 ) * 5 ; //don't let it into the ground
}
else
{
for ( i = 0 ; i < 3 ; i + + )
{
angles [ i ] = le - > angles [ i ] ;
}
}
VectorCopy ( angles , ent - > angles ) ;
angles [ 0 ] * = - 1 ;
AngleVectors ( angles , ent - > axis [ 0 ] , ent - > axis [ 1 ] , ent - > axis [ 2 ] ) ;
VectorInverse ( ent - > axis [ 1 ] ) ;
if ( ent - > keynum < = MAX_CLIENTS
# ifdef NQPROT
& & cls . protocol = = CP_QUAKEWORLD
# endif
)
ent - > keynum + = MAX_EDICTS ;
if ( state - > tagentity )
{ //ent is attached to a tag, rotate this ent accordingly.
CL_RotateAroundTag ( ent , state - > number , state - > tagentity , state - > tagindex ) ;
}
// add automatic particle trails
if ( ! model | | ( ! ( model - > flags & ~ EF_ROTATE ) & & model - > particletrail < 0 & & model - > particleeffect < 0 ) )
continue ;
if ( ! cls . allow_anyparticles & & ! ( model - > flags & ~ EF_ROTATE ) )
continue ;
// scan the old entity display list for a matching
for ( i = 0 ; i < cl_oldnumvisedicts ; i + + )
{
if ( cl_oldvisedicts [ i ] . keynum = = ent - > keynum )
{
VectorCopy ( cl_oldvisedicts [ i ] . origin , old_origin ) ;
break ;
}
}
if ( i = = cl_oldnumvisedicts )
{
P_DelinkTrailstate ( & ( cl . lerpents [ state - > number ] . trailstate ) ) ;
P_DelinkTrailstate ( & ( cl . lerpents [ state - > number ] . emitstate ) ) ;
continue ; // not in last message
}
for ( i = 0 ; i < 3 ; i + + )
2005-11-26 23:23:03 +00:00
{
2005-11-26 03:02:55 +00:00
if ( abs ( old_origin [ i ] - ent - > origin [ i ] ) > 128 )
{ // no trail if too far
VectorCopy ( ent - > origin , old_origin ) ;
break ;
}
2005-11-26 23:23:03 +00:00
}
2005-11-26 03:02:55 +00:00
2005-11-26 23:23:03 +00:00
if ( model - > particletrail > = 0 )
{
if ( P_ParticleTrail ( old_origin , ent - > origin , model - > particletrail , & ( le - > trailstate ) ) )
P_ParticleTrailIndex ( old_origin , ent - > origin , model - > traildefaultindex , 0 , & ( le - > trailstate ) ) ;
}
2005-11-26 03:02:55 +00:00
{
extern cvar_t gl_part_flame ;
if ( cls . allow_anyparticles & & gl_part_flame . value )
{
P_EmitEffect ( ent - > origin , model - > particleeffect , & ( le - > emitstate ) ) ;
}
}
//dlights are not so customisable.
if ( r_rocketlight . value )
{
float rad = 0 ;
vec3_t dclr ;
dclr [ 0 ] = 0.20 ;
dclr [ 1 ] = 0.10 ;
dclr [ 2 ] = 0 ;
if ( model - > flags & EF_ROCKET )
{
if ( strncmp ( model - > name , " models/sflesh " , 13 ) )
{ //hmm. hexen spider gibs...
rad = 200 ;
dclr [ 2 ] = 0.05 ;
}
}
else if ( model - > flags & EF_FIREBALL )
{
rad = 120 - ( rand ( ) % 20 ) ;
}
else if ( model - > flags & EF_ACIDBALL )
{
rad = 120 - ( rand ( ) % 20 ) ;
}
else if ( model - > flags & EF_SPIT )
{
// as far as I can tell this effect inverses the light...
dclr [ 0 ] = - dclr [ 0 ] ;
dclr [ 0 ] = - dclr [ 1 ] ;
dclr [ 0 ] = - dclr [ 2 ] ;
rad = 120 - ( rand ( ) % 20 ) ;
}
if ( rad )
{
dl = CL_AllocDlight ( state - > number ) ;
VectorCopy ( ent - > origin , dl - > origin ) ;
dl - > die = ( float ) cl . time ;
if ( model - > flags & EF_ROCKET )
dl - > origin [ 2 ] + = 1 ; // is this even necessary
dl - > radius = rad * bound ( 0 , r_rocketlight . value , 1 ) ;
VectorCopy ( dclr , dl - > color ) ;
}
}
}
}
# else
2004-08-23 00:15:46 +00:00
void CL_LinkPacketEntities ( void )
{
entity_t * ent ;
packet_entities_t * pack ;
2005-08-11 04:14:33 +00:00
entity_state_t * s1 ;
2004-08-23 00:15:46 +00:00
float f ;
model_t * model ;
vec3_t old_origin ;
float autorotate ;
int i ;
2004-11-27 08:16:25 +00:00
int pnum ;
//, spnum;
2004-08-23 00:15:46 +00:00
dlight_t * dl ;
2004-11-17 17:55:19 +00:00
vec3_t angles ;
2005-01-17 17:40:37 +00:00
int flicker ;
2004-08-23 00:15:46 +00:00
2005-05-26 12:55:34 +00:00
pack = & cl . frames [ cls . netchan . incoming_sequence & UPDATE_MASK ] . packet_entities ;
2004-08-23 00:15:46 +00:00
autorotate = anglemod ( 100 * cl . time ) ;
for ( pnum = 0 ; pnum < pack - > num_entities ; pnum + + )
{
s1 = & pack - > entities [ pnum ] ;
2005-06-04 04:20:20 +00:00
if ( cl_numvisedicts = = MAX_VISEDICTS )
{
Con_Printf ( " Too many visible entities \n " ) ;
break ;
}
2005-04-16 16:21:27 +00:00
ent = & cl_visedicts [ cl_numvisedicts ] ;
# ifdef Q3SHADERS
ent - > forcedshader = NULL ;
# endif
2005-10-01 03:09:17 +00:00
if ( cl_nolerp . value )
f = 1 ;
2005-04-16 16:21:27 +00:00
else
2005-10-01 03:09:17 +00:00
{
//figure out the lerp factor
if ( cl . lerpents [ s1 - > number ] . lerprate < = 0 )
f = 0 ;
else
f = ( cl . servertime - cl . lerpents [ s1 - > number ] . lerptime ) / cl . lerpents [ s1 - > number ] . lerprate ; //(cl.gametime-cl.oldgametime);//1-(cl.time-cl.lerpents[s1->number].lerptime)/cl.lerpents[s1->number].lerprate;
if ( f < 0 )
f = 0 ;
if ( f > 1 )
f = 1 ;
}
ent - > lerpfrac = 1 - ( cl . servertime - cl . lerpents [ s1 - > number ] . lerptime ) / cl . lerpents [ s1 - > number ] . lerprate ;
2005-04-18 17:12:18 +00:00
if ( ent - > lerpfrac < 0 )
ent - > lerpfrac = 0 ;
if ( ent - > lerpfrac > 1 )
ent - > lerpfrac = 1 ;
2005-10-01 03:09:17 +00:00
// if (s1->modelindex == 87 && !cl.paused)
// Con_Printf("%f %f\n", f, cl.lerpents[s1->number].lerptime-cl.servertime);
2005-04-16 16:21:27 +00:00
// calculate origin
for ( i = 0 ; i < 3 ; i + + )
2005-04-18 17:12:18 +00:00
ent - > origin [ i ] = cl . lerpents [ s1 - > number ] . origin [ i ] +
f * ( s1 - > origin [ i ] - cl . lerpents [ s1 - > number ] . origin [ i ] ) ;
2005-04-16 16:21:27 +00:00
2005-01-17 17:40:37 +00:00
//bots or powerup glows. Bots always glow, powerups can be disabled
2005-02-09 19:32:09 +00:00
if ( s1 - > modelindex ! = cl_playerindex & & r_powerupglow . value ) ;
2005-01-17 17:40:37 +00:00
{
flicker = r_lightflicker . value ? ( rand ( ) & 31 ) : 0 ;
// spawn light flashes, even ones coming from invisible objects
if ( ( s1 - > effects & ( EF_BLUE | EF_RED ) ) = = ( EF_BLUE | EF_RED ) )
CL_NewDlight ( s1 - > number , s1 - > origin [ 0 ] , s1 - > origin [ 1 ] , s1 - > origin [ 2 ] , 200 + flicker , 0 , 3 ) ;
else if ( s1 - > effects & EF_BLUE )
CL_NewDlight ( s1 - > number , s1 - > origin [ 0 ] , s1 - > origin [ 1 ] , s1 - > origin [ 2 ] , 200 + flicker , 0 , 1 ) ;
else if ( s1 - > effects & EF_RED )
CL_NewDlight ( s1 - > number , s1 - > origin [ 0 ] , s1 - > origin [ 1 ] , s1 - > origin [ 2 ] , 200 + flicker , 0 , 2 ) ;
else if ( s1 - > effects & EF_BRIGHTLIGHT )
CL_NewDlight ( s1 - > number , s1 - > origin [ 0 ] , s1 - > origin [ 1 ] , s1 - > origin [ 2 ] + 16 , 400 + flicker , 0 , 0 ) ;
else if ( s1 - > effects & EF_DIMLIGHT )
CL_NewDlight ( s1 - > number , s1 - > origin [ 0 ] , s1 - > origin [ 1 ] , s1 - > origin [ 2 ] , 200 + flicker , 0 , 0 ) ;
}
2005-08-07 18:08:13 +00:00
if ( s1 - > light [ 3 ] )
{
CL_NewDlightRGB ( s1 - > number , s1 - > origin [ 0 ] , s1 - > origin [ 1 ] , s1 - > origin [ 2 ] , s1 - > light [ 3 ] , 0 , s1 - > light [ 0 ] / 1024.0f , s1 - > light [ 1 ] / 1024.0f , s1 - > light [ 2 ] / 1024.0f ) ;
}
2004-08-23 00:15:46 +00:00
// if set to invisible, skip
2004-12-08 04:14:52 +00:00
if ( s1 - > modelindex < 1 )
2004-08-23 00:15:46 +00:00
continue ;
// create a new entity
if ( cl_numvisedicts = = MAX_VISEDICTS )
break ; // object list is full
2005-01-18 20:15:20 +00:00
if ( CL_FilterModelindex ( s1 - > modelindex , s1 - > frame ) )
continue ;
2004-08-23 00:15:46 +00:00
model = cl . model_precache [ s1 - > modelindex ] ;
if ( ! model )
{
2005-09-08 22:52:46 +00:00
Con_DPrintf ( " Bad modelindex (%i) \n " , s1 - > modelindex ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
cl_numvisedicts + + ;
2005-08-06 22:39:28 +00:00
2005-10-01 15:44:36 +00:00
# ifdef Q3SHADERS
ent - > forcedshader = NULL ;
# endif
2004-08-23 00:15:46 +00:00
ent - > visframe = 0 ;
ent - > keynum = s1 - > number ;
2005-01-17 17:40:37 +00:00
2005-07-01 19:23:00 +00:00
if ( cl_r2g . value & & s1 - > modelindex = = cl_rocketindex & & cl_rocketindex & & cl_grenadeindex )
2005-01-17 17:40:37 +00:00
ent - > model = cl . model_precache [ cl_grenadeindex ] ;
else
ent - > model = model ;
2004-08-23 00:15:46 +00:00
2005-05-15 18:49:04 +00:00
ent - > flags = s1 - > flags ;
2005-04-16 16:21:27 +00:00
if ( s1 - > effects & NQEF_ADDATIVE )
ent - > flags | = Q2RF_ADDATIVE ;
2005-08-26 22:56:51 +00:00
if ( s1 - > effects & EF_NODEPTHTEST )
ent - > flags | = RF_NODEPTHTEST ;
2004-08-23 00:15:46 +00:00
// set colormap
2005-02-06 02:47:36 +00:00
if ( s1 - > colormap & & ( s1 - > colormap < = MAX_CLIENTS )
2004-11-27 08:16:25 +00:00
& & ( gl_nocolors . value = = - 1 | | ( ent - > model /* && s1->modelindex == cl_playerindex*/ ) ) )
2004-08-23 00:15:46 +00:00
{
ent - > colormap = cl . players [ s1 - > colormap - 1 ] . translations ;
ent - > scoreboard = & cl . players [ s1 - > colormap - 1 ] ;
}
else
{
ent - > colormap = vid . colormap ;
ent - > scoreboard = NULL ;
}
// set skin
ent - > skinnum = s1 - > skinnum ;
ent - > abslight = s1 - > abslight ;
2005-05-15 18:49:04 +00:00
ent - > drawflags = s1 - > hexen2flags ;
2004-08-23 00:15:46 +00:00
// set frame
ent - > frame = s1 - > frame ;
ent - > oldframe = cl . lerpents [ s1 - > number ] . frame ;
2005-10-01 03:09:17 +00:00
ent - > frame1time = cl . servertime - cl . lerpents [ s1 - > number ] . framechange ;
ent - > frame2time = cl . servertime - cl . lerpents [ s1 - > number ] . oldframechange ;
2004-08-23 00:15:46 +00:00
// f = (sin(realtime)+1)/2;
# ifdef PEXT_SCALE
//set scale
2005-07-01 19:23:00 +00:00
ent - > scale = s1 - > scale / 16.0 ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_TRANS
//set trans
2005-07-01 19:23:00 +00:00
ent - > alpha = s1 - > trans / 255.0 ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_FATNESS
//set trans
2005-07-01 19:23:00 +00:00
ent - > fatness = s1 - > fatness / 2.0 ;
2004-08-23 00:15:46 +00:00
# endif
// rotate binary objects locally
if ( model & & model - > flags & EF_ROTATE )
{
2004-11-17 17:55:19 +00:00
angles [ 0 ] = 0 ;
angles [ 1 ] = autorotate ;
angles [ 2 ] = 0 ;
2004-08-23 00:15:46 +00:00
if ( cl_item_bobbing . value )
ent - > origin [ 2 ] + = 5 + sin ( cl . time * 3 ) * 5 ; //don't let it into the ground
}
else
{
float a1 , a2 ;
for ( i = 0 ; i < 3 ; i + + )
{
a1 = cl . lerpents [ s1 - > number ] . angles [ i ] ;
a2 = s1 - > angles [ i ] ;
if ( a1 - a2 > 180 )
a1 - = 360 ;
if ( a1 - a2 < - 180 )
a1 + = 360 ;
2005-05-13 10:42:48 +00:00
angles [ i ] = a1 + f * ( a2 - a1 ) ;
2004-08-23 00:15:46 +00:00
}
}
2004-11-17 17:55:19 +00:00
VectorCopy ( angles , ent - > angles ) ;
angles [ 0 ] * = - 1 ;
AngleVectors ( angles , ent - > axis [ 0 ] , ent - > axis [ 1 ] , ent - > axis [ 2 ] ) ;
VectorInverse ( ent - > axis [ 1 ] ) ;
2005-05-13 10:42:48 +00:00
if ( ent - > keynum < = MAX_CLIENTS
# ifdef NQPROT
2005-07-01 19:23:00 +00:00
& & cls . protocol = = CP_QUAKEWORLD
2005-05-13 10:42:48 +00:00
# endif
)
2005-03-28 00:11:59 +00:00
ent - > keynum + = MAX_EDICTS ;
2005-07-01 19:23:00 +00:00
if ( s1 - > tagentity )
{ //ent is attached to a tag, rotate this ent accordingly.
CL_RotateAroundTag ( ent , s1 - > number , s1 - > tagentity , s1 - > tagindex ) ;
}
2004-08-23 00:15:46 +00:00
// add automatic particle trails
2005-09-09 02:01:30 +00:00
if ( ! model | | ( ! ( model - > flags & ~ EF_ROTATE ) & & model - > particletrail < 0 & & model - > particleeffect < 0 ) )
2004-08-23 00:15:46 +00:00
continue ;
if ( ! cls . allow_anyparticles & & ! ( model - > flags & ~ EF_ROTATE ) )
continue ;
// scan the old entity display list for a matching
for ( i = 0 ; i < cl_oldnumvisedicts ; i + + )
{
if ( cl_oldvisedicts [ i ] . keynum = = ent - > keynum )
{
VectorCopy ( cl_oldvisedicts [ i ] . origin , old_origin ) ;
break ;
}
}
if ( i = = cl_oldnumvisedicts )
{
2005-05-30 04:34:47 +00:00
P_DelinkTrailstate ( & ( cl . lerpents [ s1 - > number ] . trailstate ) ) ;
2005-08-06 22:39:28 +00:00
P_DelinkTrailstate ( & ( cl . lerpents [ s1 - > number ] . emitstate ) ) ;
2004-08-23 00:15:46 +00:00
continue ; // not in last message
}
for ( i = 0 ; i < 3 ; i + + )
2005-11-26 23:23:03 +00:00
{
2004-08-23 00:15:46 +00:00
if ( abs ( old_origin [ i ] - ent - > origin [ i ] ) > 128 )
{ // no trail if too far
VectorCopy ( ent - > origin , old_origin ) ;
break ;
}
2005-11-26 23:23:03 +00:00
}
2004-08-23 00:15:46 +00:00
2005-11-26 23:23:03 +00:00
if ( model - > particletrail > = 0 )
{
if ( P_ParticleTrail ( old_origin , ent - > origin , model - > particletrail , & cl . lerpents [ s1 - > number ] . trailstate ) )
P_ParticleTrailIndex ( old_origin , ent - > origin , model - > traildefaultindex , 0 , & cl . lerpents [ s1 - > number ] . trailstate ) ;
}
2004-08-23 00:15:46 +00:00
2005-09-09 02:01:30 +00:00
{
extern cvar_t gl_part_flame ;
if ( cls . allow_anyparticles & & gl_part_flame . value )
{
P_EmitEffect ( ent - > origin , model - > particleeffect , & ( cl . lerpents [ s1 - > number ] . emitstate ) ) ;
}
}
2005-01-17 17:40:37 +00:00
//dlights are not so customisable.
if ( r_rocketlight . value )
2004-08-23 00:15:46 +00:00
{
2005-08-28 05:21:25 +00:00
float rad = 0 ;
vec3_t dclr ;
dclr [ 0 ] = 0.20 ;
dclr [ 1 ] = 0.10 ;
dclr [ 2 ] = 0 ;
2005-01-17 17:40:37 +00:00
if ( model - > flags & EF_ROCKET )
{
if ( strncmp ( model - > name , " models/sflesh " , 13 ) )
{ //hmm. hexen spider gibs...
2005-08-28 05:21:25 +00:00
rad = 200 ;
dclr [ 2 ] = 0.05 ;
2005-01-17 17:40:37 +00:00
}
}
else if ( model - > flags & EF_FIREBALL )
{
2005-08-28 05:21:25 +00:00
rad = 120 - ( rand ( ) % 20 ) ;
2005-01-17 17:40:37 +00:00
}
else if ( model - > flags & EF_ACIDBALL )
{
2005-08-28 05:21:25 +00:00
rad = 120 - ( rand ( ) % 20 ) ;
2005-01-17 17:40:37 +00:00
}
else if ( model - > flags & EF_SPIT )
{
2005-10-05 02:08:28 +00:00
// as far as I can tell this effect inverses the light...
dclr [ 0 ] = - dclr [ 0 ] ;
2005-11-26 23:11:19 +00:00
dclr [ 1 ] = - dclr [ 1 ] ;
dclr [ 2 ] = - dclr [ 2 ] ;
2005-10-05 02:08:28 +00:00
rad = 120 - ( rand ( ) % 20 ) ;
2005-08-28 05:21:25 +00:00
}
if ( rad )
{
dl = CL_AllocDlight ( s1 - > number ) ;
2005-01-17 17:40:37 +00:00
VectorCopy ( ent - > origin , dl - > origin ) ;
2004-11-27 08:16:25 +00:00
dl - > die = ( float ) cl . time ;
2005-08-28 05:21:25 +00:00
if ( model - > flags & EF_ROCKET )
dl - > origin [ 2 ] + = 1 ; // is this even necessary
dl - > radius = rad * bound ( 0 , r_rocketlight . value , 1 ) ;
VectorCopy ( dclr , dl - > color ) ;
2004-08-23 00:15:46 +00:00
}
2005-08-28 05:21:25 +00:00
2004-08-23 00:15:46 +00:00
}
}
}
2005-11-26 03:02:55 +00:00
# endif
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
PROJECTILE PARSING / LINKING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
typedef struct
{
int modelindex ;
vec3_t origin ;
vec3_t angles ;
} projectile_t ;
# define MAX_PROJECTILES 32
projectile_t cl_projectiles [ MAX_PROJECTILES ] ;
int cl_num_projectiles ;
extern int cl_spikeindex ;
void CL_ClearProjectiles ( void )
{
cl_num_projectiles = 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = =
CL_ParseProjectiles
Nails are passed as efficient temporary entities
= = = = = = = = = = = = = = = = = = = = =
*/
2004-12-08 04:14:52 +00:00
void CL_ParseProjectiles ( int modelindex , qboolean nails2 )
2004-08-23 00:15:46 +00:00
{
int i , c , j ;
qbyte bits [ 6 ] ;
projectile_t * pr ;
c = MSG_ReadByte ( ) ;
for ( i = 0 ; i < c ; i + + )
{
2004-12-08 04:14:52 +00:00
if ( nails2 )
MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
for ( j = 0 ; j < 6 ; j + + )
bits [ j ] = MSG_ReadByte ( ) ;
if ( cl_num_projectiles = = MAX_PROJECTILES )
continue ;
pr = & cl_projectiles [ cl_num_projectiles ] ;
cl_num_projectiles + + ;
pr - > modelindex = modelindex ;
pr - > origin [ 0 ] = ( ( bits [ 0 ] + ( ( bits [ 1 ] & 15 ) < < 8 ) ) < < 1 ) - 4096 ;
pr - > origin [ 1 ] = ( ( ( bits [ 1 ] > > 4 ) + ( bits [ 2 ] < < 4 ) ) < < 1 ) - 4096 ;
pr - > origin [ 2 ] = ( ( bits [ 3 ] + ( ( bits [ 4 ] & 15 ) < < 8 ) ) < < 1 ) - 4096 ;
2004-12-24 08:45:56 +00:00
pr - > angles [ 0 ] = 360 * ( ( int ) bits [ 4 ] > > 4 ) / 16.0f ;
pr - > angles [ 1 ] = 360 * ( int ) bits [ 5 ] / 256.0f ;
2004-08-23 00:15:46 +00:00
}
}
/*
= = = = = = = = = = = = =
CL_LinkProjectiles
= = = = = = = = = = = = =
*/
void CL_LinkProjectiles ( void )
{
int i ;
projectile_t * pr ;
entity_t * ent ;
for ( i = 0 , pr = cl_projectiles ; i < cl_num_projectiles ; i + + , pr + + )
{
// grab an entity to fill in
if ( cl_numvisedicts = = MAX_VISEDICTS )
break ; // object list is full
ent = & cl_visedicts [ cl_numvisedicts ] ;
cl_numvisedicts + + ;
ent - > keynum = 0 ;
if ( pr - > modelindex < 1 )
continue ;
2005-12-01 01:56:37 +00:00
# ifdef Q3SHADERS
2005-11-30 23:12:08 +00:00
ent - > forcedshader = NULL ;
2005-12-01 01:56:37 +00:00
# endif
2004-08-23 00:15:46 +00:00
ent - > model = cl . model_precache [ pr - > modelindex ] ;
ent - > skinnum = 0 ;
ent - > frame = 0 ;
2005-07-08 00:37:52 +00:00
ent - > flags = 0 ;
2005-12-22 21:46:28 +00:00
# ifdef SWQUAKE
2005-12-22 20:35:04 +00:00
ent - > palremap = D_IdentityRemap ( ) ;
2005-12-22 21:46:28 +00:00
# endif
2004-08-23 00:15:46 +00:00
ent - > scoreboard = NULL ;
# ifdef PEXT_SCALE
ent - > scale = 1 ;
# endif
# ifdef PEXT_TRANS
ent - > alpha = 1 ;
# endif
VectorCopy ( pr - > origin , ent - > origin ) ;
VectorCopy ( pr - > angles , ent - > angles ) ;
2004-12-24 08:45:56 +00:00
ent - > angles [ 0 ] * = - 1 ;
AngleVectors ( ent - > angles , ent - > axis [ 0 ] , ent - > axis [ 1 ] , ent - > axis [ 2 ] ) ;
VectorInverse ( ent - > axis [ 1 ] ) ;
ent - > angles [ 0 ] * = - 1 ;
2004-08-23 00:15:46 +00:00
}
}
//========================================
2005-01-17 17:40:37 +00:00
extern int cl_spikeindex , cl_playerindex , cl_flagindex , cl_rocketindex , cl_grenadeindex ;
2004-08-23 00:15:46 +00:00
entity_t * CL_NewTempEntity ( void ) ;
# define DF_ORIGIN 1
# define DF_ANGLES (1<<3)
# define DF_EFFECTS (1<<6)
# define DF_SKINNUM (1<<7)
# define DF_DEAD (1<<8)
# define DF_GIB (1<<9)
# define DF_WEAPONFRAME (1<<10)
# define DF_MODEL (1<<11)
static int MVD_TranslateFlags ( int src )
{
int dst = 0 ;
if ( src & DF_EFFECTS )
dst | = PF_EFFECTS ;
if ( src & DF_SKINNUM )
dst | = PF_SKINNUM ;
if ( src & DF_DEAD )
dst | = PF_DEAD ;
if ( src & DF_GIB )
dst | = PF_GIB ;
if ( src & DF_WEAPONFRAME )
dst | = PF_WEAPONFRAME ;
if ( src & DF_MODEL )
dst | = PF_MODEL ;
return dst ;
}
/*
= = = = = = = = = = = = = = = = = = =
CL_ParsePlayerinfo
= = = = = = = = = = = = = = = = = = =
*/
2005-04-26 16:04:12 +00:00
extern int parsecountmod , oldparsecountmod ;
2004-08-23 00:15:46 +00:00
extern double parsecounttime ;
int lastplayerinfo ;
void CL_ParsePlayerinfo ( void )
{
int msec ;
unsigned int flags ;
player_info_t * info ;
2005-04-26 16:04:12 +00:00
player_state_t * state , * oldstate ;
2004-08-23 00:15:46 +00:00
int num ;
int i ;
int new ;
2004-09-13 02:19:15 +00:00
vec3_t org ;
2004-08-23 00:15:46 +00:00
lastplayerinfo = num = MSG_ReadByte ( ) ;
if ( num > = MAX_CLIENTS )
Host_EndGame ( " CL_ParsePlayerinfo: bad num " ) ;
info = & cl . players [ num ] ;
2005-04-26 16:04:12 +00:00
oldstate = & cl . frames [ oldparsecountmod ] . playerstate [ num ] ;
2004-08-23 00:15:46 +00:00
state = & cl . frames [ parsecountmod ] . playerstate [ num ] ;
if ( cls . demoplayback = = DPB_MVD )
{
player_state_t * prevstate , dummy ;
if ( ! cl . parsecount | | info - > prevcount > cl . parsecount | | cl . parsecount - info - > prevcount > = UPDATE_BACKUP - 1 )
{
memset ( & dummy , 0 , sizeof ( dummy ) ) ;
prevstate = & dummy ;
}
else
{
prevstate = & cl . frames [ info - > prevcount & UPDATE_MASK ] . playerstate [ num ] ;
}
memcpy ( state , prevstate , sizeof ( player_state_t ) ) ;
2004-08-27 00:37:05 +00:00
info - > prevcount = cl . parsecount ;
2004-08-23 00:15:46 +00:00
2005-11-30 01:20:53 +00:00
if ( cls . findtrack & & info - > stats [ STAT_HEALTH ] > 0 )
2004-08-23 00:15:46 +00:00
{
2005-11-30 01:20:53 +00:00
// extern int ideal_track;
autocam [ 0 ] = CAM_TRACK ;
Cam_Lock ( 0 , num ) ;
// ideal_track = num;
2004-08-23 00:15:46 +00:00
cls . findtrack = false ;
}
2005-11-30 01:20:53 +00:00
2004-08-23 00:15:46 +00:00
flags = MSG_ReadShort ( ) ;
state - > flags = MVD_TranslateFlags ( flags ) ;
state - > messagenum = cl . parsecount ;
state - > command . msec = 0 ;
state - > frame = MSG_ReadByte ( ) ;
state - > state_time = parsecounttime ;
state - > command . msec = 0 ;
for ( i = 0 ; i < 3 ; i + + )
{
if ( flags & ( DF_ORIGIN < < i ) )
state - > origin [ i ] = MSG_ReadCoord ( ) ;
}
for ( i = 0 ; i < 3 ; i + + )
{
if ( flags & ( DF_ANGLES < < i ) )
2004-08-27 00:37:05 +00:00
{
state - > command . angles [ i ] = MSG_ReadShort ( ) ;
}
state - > viewangles [ i ] = state - > command . angles [ i ] * ( 360.0 / 65536 ) ;
2004-08-23 00:15:46 +00:00
}
if ( flags & DF_MODEL )
state - > modelindex = MSG_ReadByte ( ) ;
if ( flags & DF_SKINNUM )
state - > skinnum = MSG_ReadByte ( ) ;
if ( flags & DF_EFFECTS )
state - > effects = MSG_ReadByte ( ) ;
if ( flags & DF_WEAPONFRAME )
state - > weaponframe = MSG_ReadByte ( ) ;
state - > hullnum = 1 ;
2005-07-01 19:23:00 +00:00
state - > scale = 1 * 16 ;
state - > trans = 255 ;
2004-08-23 00:15:46 +00:00
state - > fatness = 0 ;
2004-08-27 00:37:05 +00:00
state - > pm_type = PM_NORMAL ;
2005-04-26 16:04:12 +00:00
TP_ParsePlayerInfo ( oldstate , state , info ) ;
2005-06-07 04:40:16 +00:00
if ( cl . splitclients < MAX_SPLITS )
{
extern cvar_t cl_splitscreen ;
if ( cl . splitclients < cl_splitscreen . value + 1 )
{
for ( i = 0 ; i < cl . splitclients ; i + + )
if ( autocam [ i ] & & spec_track [ i ] = = num )
return ;
if ( i = = cl . splitclients )
{
autocam [ cl . splitclients ] = CAM_TRACK ;
spec_track [ cl . splitclients ] = num ;
cl . splitclients + + ;
}
}
}
2004-08-23 00:15:46 +00:00
return ;
}
flags = state - > flags = ( unsigned short ) MSG_ReadShort ( ) ;
if ( cls . z_ext & Z_EXT_PM_TYPE )
if ( flags & PF_EXTRA_PFS )
flags | = MSG_ReadByte ( ) < < 16 ;
state - > messagenum = cl . parsecount ;
2004-09-07 18:22:30 +00:00
org [ 0 ] = MSG_ReadCoord ( ) ;
org [ 1 ] = MSG_ReadCoord ( ) ;
org [ 2 ] = MSG_ReadCoord ( ) ;
VectorCopy ( org , state - > origin ) ;
2004-08-23 00:15:46 +00:00
new = MSG_ReadByte ( ) ;
if ( state - > frame ! = new )
{
// state->lerpstarttime = realtime;
state - > frame = new ;
}
// the other player's last move was likely some time
// before the packet was sent out, so accurately track
// the exact time it was valid at
if ( flags & PF_MSEC )
{
msec = MSG_ReadByte ( ) ;
state - > state_time = parsecounttime - msec * 0.001 ;
}
else
state - > state_time = parsecounttime ;
if ( flags & PF_COMMAND )
{
MSG_ReadDeltaUsercmd ( & nullcmd , & state - > command ) ;
state - > viewangles [ 0 ] = state - > command . angles [ 0 ] * ( 360.0 / 65536 ) ;
state - > viewangles [ 1 ] = state - > command . angles [ 1 ] * ( 360.0 / 65536 ) ;
state - > viewangles [ 2 ] = state - > command . angles [ 2 ] * ( 360.0 / 65536 ) ;
}
for ( i = 0 ; i < 3 ; i + + )
{
if ( flags & ( PF_VELOCITY1 < < i ) )
state - > velocity [ i ] = MSG_ReadShort ( ) ;
else
state - > velocity [ i ] = 0 ;
}
if ( flags & PF_MODEL )
state - > modelindex = MSG_ReadByte ( ) ;
else
state - > modelindex = cl_playerindex ;
if ( flags & PF_SKINNUM )
{
state - > skinnum = MSG_ReadByte ( ) ;
if ( state - > skinnum & ( 1 < < 7 ) & & ( flags & PF_MODEL ) )
{
state - > modelindex + = 256 ;
state - > skinnum - = ( 1 < < 7 ) ;
}
}
else
state - > skinnum = 0 ;
if ( flags & PF_EFFECTS )
state - > effects = MSG_ReadByte ( ) ;
else
state - > effects = 0 ;
if ( flags & PF_WEAPONFRAME )
state - > weaponframe = MSG_ReadByte ( ) ;
else
state - > weaponframe = 0 ;
2005-05-19 02:53:03 +00:00
if ( cl . worldmodel & & ( cl . worldmodel - > fromgame = = fg_quake | | cl . worldmodel - > fromgame = = fg_halflife ) )
2005-04-16 16:21:27 +00:00
state - > hullnum = 1 ;
else
state - > hullnum = 56 ;
2005-07-01 19:23:00 +00:00
state - > scale = 1 * 16 ;
state - > trans = 255 ;
2004-08-23 00:15:46 +00:00
state - > fatness = 0 ;
# ifdef PEXT_SCALE
2005-07-01 19:23:00 +00:00
if ( flags & PF_SCALE_Z & & cls . fteprotocolextensions & PEXT_SCALE )
state - > scale = ( float ) MSG_ReadByte ( ) / 100 ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_TRANS
2005-07-01 19:23:00 +00:00
if ( flags & PF_TRANS_Z & & cls . fteprotocolextensions & PEXT_TRANS )
state - > trans = ( float ) MSG_ReadByte ( ) / 255 ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_FATNESS
2005-07-01 19:23:00 +00:00
if ( flags & PF_FATNESS_Z & & cls . fteprotocolextensions & PEXT_FATNESS )
state - > fatness = ( float ) MSG_ReadChar ( ) / 2 ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_HULLSIZE
2005-07-01 19:23:00 +00:00
if ( cls . fteprotocolextensions & PEXT_HULLSIZE )
{
if ( flags & PF_HULLSIZE_Z )
state - > hullnum = MSG_ReadByte ( ) ;
}
2004-08-23 00:15:46 +00:00
//should be passed to player move func.
# endif
2005-07-01 19:23:00 +00:00
if ( cls . z_ext & Z_EXT_PM_TYPE )
{
int pm_code ;
2004-08-23 00:15:46 +00:00
pm_code = ( flags & PF_PMC_MASK ) > > PF_PMC_SHIFT ;
if ( pm_code = = PMC_NORMAL | | pm_code = = PMC_NORMAL_JUMP_HELD )
{
if ( flags & PF_DEAD )
state - > pm_type = PM_DEAD ;
else
{
state - > pm_type = PM_NORMAL ;
state - > jump_held = ( pm_code = = PMC_NORMAL_JUMP_HELD ) ;
}
}
else if ( pm_code = = PMC_OLD_SPECTATOR )
state - > pm_type = PM_OLD_SPECTATOR ;
else
{
if ( cls . z_ext & Z_EXT_PM_TYPE_NEW )
{
if ( pm_code = = PMC_SPECTATOR )
state - > pm_type = PM_SPECTATOR ;
else if ( pm_code = = PMC_FLY )
state - > pm_type = PM_FLY ;
else if ( pm_code = = PMC_NONE )
state - > pm_type = PM_NONE ;
else if ( pm_code = = PMC_FREEZE )
state - > pm_type = PM_FREEZE ;
else {
// future extension?
goto guess_pm_type ;
}
}
else
{
// future extension?
goto guess_pm_type ;
}
}
}
else
{
guess_pm_type :
if ( cl . players [ num ] . spectator )
state - > pm_type = PM_OLD_SPECTATOR ;
else if ( flags & PF_DEAD )
state - > pm_type = PM_DEAD ;
else
state - > pm_type = PM_NORMAL ;
}
2005-08-26 22:56:51 +00:00
if ( cl . lerpplayers [ num ] . frame ! = state - > frame )
{
cl . lerpplayers [ num ] . oldframechange = cl . lerpplayers [ num ] . framechange ;
cl . lerpplayers [ num ] . framechange = cl . time ;
cl . lerpplayers [ num ] . frame = state - > frame ;
//don't care about position interpolation.
}
2005-07-16 00:53:08 +00:00
TP_ParsePlayerInfo ( oldstate , state , info ) ;
2004-08-23 00:15:46 +00:00
}
void CL_ParseClientPersist ( void )
{
player_info_t * info ;
int flags ;
flags = MSG_ReadShort ( ) ;
info = & cl . players [ lastplayerinfo ] ;
if ( flags & 1 )
info - > vweapindex = MSG_ReadShort ( ) ;
}
/*
= = = = = = = = = = = = = = = =
CL_AddFlagModels
Called when the CTF flags are set
= = = = = = = = = = = = = = = =
*/
void CL_AddFlagModels ( entity_t * ent , int team )
{
int i ;
float f ;
vec3_t v_forward , v_right , v_up ;
entity_t * newent ;
2004-11-17 17:55:19 +00:00
vec3_t angles ;
2004-08-23 00:15:46 +00:00
if ( cl_flagindex = = - 1 )
return ;
f = 14 ;
if ( ent - > frame > = 29 & & ent - > frame < = 40 ) {
if ( ent - > frame > = 29 & & ent - > frame < = 34 ) { //axpain
2005-02-06 02:47:36 +00:00
if ( ent - > frame = = 29 ) f = f + 2 ;
2004-08-23 00:15:46 +00:00
else if ( ent - > frame = = 30 ) f = f + 8 ;
else if ( ent - > frame = = 31 ) f = f + 12 ;
else if ( ent - > frame = = 32 ) f = f + 11 ;
else if ( ent - > frame = = 33 ) f = f + 10 ;
else if ( ent - > frame = = 34 ) f = f + 4 ;
} else if ( ent - > frame > = 35 & & ent - > frame < = 40 ) { // pain
2005-02-06 02:47:36 +00:00
if ( ent - > frame = = 35 ) f = f + 2 ;
2004-08-23 00:15:46 +00:00
else if ( ent - > frame = = 36 ) f = f + 10 ;
else if ( ent - > frame = = 37 ) f = f + 10 ;
else if ( ent - > frame = = 38 ) f = f + 8 ;
else if ( ent - > frame = = 39 ) f = f + 4 ;
else if ( ent - > frame = = 40 ) f = f + 2 ;
}
} else if ( ent - > frame > = 103 & & ent - > frame < = 118 ) {
if ( ent - > frame > = 103 & & ent - > frame < = 104 ) f = f + 6 ; //nailattack
2005-02-06 02:47:36 +00:00
else if ( ent - > frame > = 105 & & ent - > frame < = 106 ) f = f + 6 ; //light
2004-08-23 00:15:46 +00:00
else if ( ent - > frame > = 107 & & ent - > frame < = 112 ) f = f + 7 ; //rocketattack
else if ( ent - > frame > = 112 & & ent - > frame < = 118 ) f = f + 7 ; //shotattack
}
newent = CL_NewTempEntity ( ) ;
newent - > model = cl . model_precache [ cl_flagindex ] ;
newent - > skinnum = team ;
AngleVectors ( ent - > angles , v_forward , v_right , v_up ) ;
v_forward [ 2 ] = - v_forward [ 2 ] ; // reverse z component
for ( i = 0 ; i < 3 ; i + + )
newent - > origin [ i ] = ent - > origin [ i ] - f * v_forward [ i ] + 22 * v_right [ i ] ;
newent - > origin [ 2 ] - = 16 ;
VectorCopy ( ent - > angles , newent - > angles )
newent - > angles [ 2 ] - = 45 ;
2004-11-17 17:55:19 +00:00
VectorCopy ( newent - > angles , angles ) ;
angles [ 0 ] * = - 1 ;
AngleVectors ( angles , newent - > axis [ 0 ] , newent - > axis [ 1 ] , newent - > axis [ 2 ] ) ;
VectorInverse ( newent - > axis [ 1 ] ) ;
2004-08-23 00:15:46 +00:00
}
void CL_AddVWeapModel ( entity_t * player , int model )
{
entity_t * newent ;
2004-11-17 17:55:19 +00:00
vec3_t angles ;
2004-08-23 00:15:46 +00:00
newent = CL_NewTempEntity ( ) ;
VectorCopy ( player - > origin , newent - > origin ) ;
VectorCopy ( player - > angles , newent - > angles ) ;
newent - > skinnum = player - > skinnum ;
newent - > model = cl . model_precache [ model ] ;
newent - > frame = player - > frame ;
2004-11-17 17:55:19 +00:00
VectorCopy ( newent - > angles , angles ) ;
angles [ 0 ] * = - 1 ;
AngleVectors ( angles , newent - > axis [ 0 ] , newent - > axis [ 1 ] , newent - > axis [ 2 ] ) ;
VectorInverse ( newent - > axis [ 1 ] ) ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = =
CL_LinkPlayers
Create visible entities in the correct position
for all current players
= = = = = = = = = = = = =
*/
void CL_LinkPlayers ( void )
{
int pnum ;
int j ;
player_info_t * info ;
player_state_t * state ;
player_state_t exact ;
double playertime ;
entity_t * ent ;
int msec ;
frame_t * frame ;
2005-10-01 03:09:17 +00:00
frame_t * fromf ;
2004-08-23 00:15:46 +00:00
int oldphysent ;
2004-11-17 17:55:19 +00:00
vec3_t angles ;
2004-08-23 00:15:46 +00:00
playertime = realtime - cls . latency + 0.02 ;
if ( playertime > realtime )
playertime = realtime ;
2005-10-01 03:09:17 +00:00
frame = & cl . frames [ cl . validsequence & UPDATE_MASK ] ;
fromf = & cl . frames [ cl . oldvalidsequence & UPDATE_MASK ] ;
2004-08-23 00:15:46 +00:00
2005-02-06 02:47:36 +00:00
for ( j = 0 , info = cl . players , state = frame - > playerstate ; j < MAX_CLIENTS
2004-08-23 00:15:46 +00:00
; j + + , info + + , state + + )
{
2005-10-01 03:09:17 +00:00
if ( state - > messagenum ! = cl . validsequence )
2004-08-23 00:15:46 +00:00
continue ; // not present this frame
// spawn light flashes, even ones coming from invisible objects
2005-02-09 19:32:09 +00:00
if ( ( ! r_flashblend . value | | j ! = cl . playernum [ 0 ] ) & & r_powerupglow . value )
2004-08-23 00:15:46 +00:00
{
if ( ( state - > effects & ( EF_BLUE | EF_RED ) ) = = ( EF_BLUE | EF_RED ) )
2005-06-14 04:52:10 +00:00
CL_NewDlight ( j + 1 , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + ( r_lightflicker . value ? ( rand ( ) & 31 ) : 0 ) , 0.1 , 3 ) - > noppl = ( j ! = cl . playernum [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
else if ( state - > effects & EF_BLUE )
2005-06-14 04:52:10 +00:00
CL_NewDlight ( j + 1 , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + ( r_lightflicker . value ? ( rand ( ) & 31 ) : 0 ) , 0.1 , 1 ) - > noppl = ( j ! = cl . playernum [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
else if ( state - > effects & EF_RED )
2005-06-14 04:52:10 +00:00
CL_NewDlight ( j + 1 , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + ( r_lightflicker . value ? ( rand ( ) & 31 ) : 0 ) , 0.1 , 2 ) - > noppl = ( j ! = cl . playernum [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
else if ( state - > effects & EF_BRIGHTLIGHT )
2005-06-14 04:52:10 +00:00
CL_NewDlight ( j + 1 , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] + 16 , 400 + ( r_lightflicker . value ? ( rand ( ) & 31 ) : 0 ) , 0.1 , 0 ) - > noppl = ( j ! = cl . playernum [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
else if ( state - > effects & EF_DIMLIGHT )
2005-06-14 04:52:10 +00:00
CL_NewDlight ( j + 1 , state - > origin [ 0 ] , state - > origin [ 1 ] , state - > origin [ 2 ] , 200 + ( r_lightflicker . value ? ( rand ( ) & 31 ) : 0 ) , 0.1 , 0 ) - > noppl = ( j ! = cl . playernum [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
}
2004-12-08 04:14:52 +00:00
if ( state - > modelindex < 1 )
2004-08-23 00:15:46 +00:00
continue ;
2005-01-18 20:15:20 +00:00
if ( CL_FilterModelindex ( state - > modelindex , state - > frame ) )
continue ;
2004-08-23 00:15:46 +00:00
/*
if ( ! Cam_DrawPlayer ( j ) )
continue ;
*/
// grab an entity to fill in
if ( cl_numvisedicts = = MAX_VISEDICTS )
break ; // object list is full
ent = & cl_visedicts [ cl_numvisedicts ] ;
cl_numvisedicts + + ;
ent - > keynum = j + 1 ;
ent - > flags = 0 ;
2005-10-01 15:44:36 +00:00
# ifdef Q3SHADERS
ent - > forcedshader = NULL ;
# endif
2004-08-23 00:15:46 +00:00
ent - > model = cl . model_precache [ state - > modelindex ] ;
2005-02-06 02:47:36 +00:00
ent - > skinnum = state - > skinnum ;
2004-08-23 00:15:46 +00:00
2005-08-26 22:56:51 +00:00
ent - > frame1time = cl . time - cl . lerpplayers [ j ] . framechange ;
ent - > frame2time = cl . time - cl . lerpplayers [ j ] . oldframechange ;
2005-07-01 19:23:00 +00:00
2004-08-23 00:15:46 +00:00
ent - > frame = state - > frame ;
ent - > oldframe = state - > oldframe ;
if ( state - > lerpstarttime )
{
2005-04-18 17:12:18 +00:00
ent - > lerpfrac = 1 - ( realtime - state - > lerpstarttime ) * 10 ;
if ( ent - > lerpfrac < 0 )
ent - > lerpfrac = 0 ;
if ( ent - > lerpfrac > 1 )
ent - > lerpfrac = 1 ;
2004-08-23 00:15:46 +00:00
}
else
2005-04-18 17:12:18 +00:00
ent - > lerpfrac = 0 ;
2004-08-23 00:15:46 +00:00
2005-12-22 21:46:28 +00:00
# ifdef SWQUAKE
2005-12-22 20:35:04 +00:00
ent - > palremap = info - > palremap ;
2005-12-22 21:46:28 +00:00
# endif
2004-08-23 00:15:46 +00:00
if ( state - > modelindex = = cl_playerindex )
ent - > scoreboard = info ; // use custom skin
else
ent - > scoreboard = NULL ;
# ifdef PEXT_SCALE
2005-07-01 19:23:00 +00:00
ent - > scale = state - > scale / 16.0f ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_TRANS
2005-07-01 19:23:00 +00:00
ent - > alpha = state - > trans / 255.0f ;
2004-08-23 00:15:46 +00:00
# endif
2005-07-01 19:23:00 +00:00
ent - > fatness = state - > fatness / 2 ;
2004-08-23 00:15:46 +00:00
//
// angles
//
2004-11-17 17:55:19 +00:00
angles [ PITCH ] = - state - > viewangles [ PITCH ] / 3 ;
angles [ YAW ] = state - > viewangles [ YAW ] ;
angles [ ROLL ] = 0 ;
angles [ ROLL ] = V_CalcRoll ( angles , state - > velocity ) * 4 ;
2004-08-23 00:15:46 +00:00
// the player object gets added with flags | 2
for ( pnum = 0 ; pnum < cl . splitclients ; pnum + + )
{
if ( j = = cl . playernum [ pnum ] )
{
2005-06-14 04:52:10 +00:00
/* if (cl.spectator)
2004-08-23 00:15:46 +00:00
{
cl_numvisedicts - - ;
continue ;
}
2005-06-14 04:52:10 +00:00
*/ angles [ 0 ] = - 1 * cl . viewangles [ pnum ] [ 0 ] / 3 ;
2004-11-17 17:55:19 +00:00
angles [ 1 ] = cl . viewangles [ pnum ] [ 1 ] ;
angles [ 2 ] = cl . viewangles [ pnum ] [ 2 ] ;
2004-08-23 00:15:46 +00:00
ent - > origin [ 0 ] = cl . simorg [ pnum ] [ 0 ] ;
ent - > origin [ 1 ] = cl . simorg [ pnum ] [ 1 ] ;
ent - > origin [ 2 ] = cl . simorg [ pnum ] [ 2 ] + cl . crouch [ pnum ] ;
ent - > flags | = 2 ;
break ;
}
}
2004-11-17 17:55:19 +00:00
VectorCopy ( angles , ent - > angles ) ;
angles [ 0 ] * = - 1 ;
AngleVectors ( angles , ent - > axis [ 0 ] , ent - > axis [ 1 ] , ent - > axis [ 2 ] ) ;
VectorInverse ( ent - > axis [ 1 ] ) ;
2004-08-23 00:15:46 +00:00
// only predict half the move to minimize overruns
msec = 500 * ( playertime - state - > state_time ) ;
2005-10-01 03:09:17 +00:00
if ( 1 )
2004-08-23 00:15:46 +00:00
{
2005-10-01 03:09:17 +00:00
float f ;
int i ;
f = ( cl . gametime - cl . servertime ) / ( cl . gametime - cl . oldgametime ) ;
if ( f < 0 )
f = 0 ;
if ( f > 1 )
f = 1 ;
for ( i = 0 ; i < 3 ; i + + )
{
ent - > origin [ i ] = state - > origin [ i ] +
f * ( fromf - > playerstate [ j ] . origin [ i ] - state - > origin [ i ] ) ;
}
}
else if ( pnum < cl . splitclients )
{ //this is a local player
2004-08-23 00:15:46 +00:00
}
else if ( msec < = 0 | | ( ! cl_predict_players . value & & ! cl_predict_players2 . value ) )
{
VectorCopy ( state - > origin , ent - > origin ) ;
//Con_DPrintf ("nopredict\n");
}
else
{
// predict players movement
if ( msec > 255 )
msec = 255 ;
state - > command . msec = msec ;
//Con_DPrintf ("predict: %i\n", msec);
oldphysent = pmove . numphysent ;
CL_SetSolidPlayers ( j ) ;
CL_PredictUsercmd ( 0 , state , & exact , & state - > command ) ; //uses player 0's maxspeed/grav...
pmove . numphysent = oldphysent ;
VectorCopy ( exact . origin , ent - > origin ) ;
}
if ( cl . worldmodel - > fromgame = = fg_halflife )
ent - > origin [ 2 ] - = 12 ;
2005-04-16 16:21:27 +00:00
if ( state - > effects & QWEF_FLAG1 )
2004-08-23 00:15:46 +00:00
CL_AddFlagModels ( ent , 0 ) ;
2005-04-16 16:21:27 +00:00
else if ( state - > effects & QWEF_FLAG2 )
2004-08-23 00:15:46 +00:00
CL_AddFlagModels ( ent , 1 ) ;
else if ( info - > vweapindex )
CL_AddVWeapModel ( ent , info - > vweapindex ) ;
}
}
2005-04-16 16:21:27 +00:00
# ifdef Q3SHADERS //fixme: do better.
# include "shader.h"
# endif
2005-02-12 18:56:04 +00:00
void CL_LinkViewModel ( void )
{
entity_t ent ;
// float ambient[4], diffuse[4];
// int j;
// int lnum;
// vec3_t dist;
// float add;
// dlight_t *dl;
// int ambientlight, shadelight;
2005-09-26 03:40:09 +00:00
static struct model_s * oldmodel [ MAX_SPLITS ] ;
2005-02-12 18:56:04 +00:00
static float lerptime [ MAX_SPLITS ] ;
static int prevframe [ MAX_SPLITS ] ;
static int oldframe [ MAX_SPLITS ] ;
# ifdef SIDEVIEWS
extern qboolean r_secondaryview ;
if ( r_secondaryview = = 1 )
return ;
# endif
if ( ! r_drawviewmodel . value | | ! Cam_DrawViewModel ( r_refdef . currentplayernum ) )
return ;
# ifdef Q2CLIENT
2005-05-26 12:55:34 +00:00
if ( cls . protocol = = CP_QUAKE2 )
2005-02-12 18:56:04 +00:00
return ;
# endif
if ( ! r_drawentities . value )
return ;
if ( cl . stats [ r_refdef . currentplayernum ] [ STAT_ITEMS ] & IT_INVISIBILITY )
return ;
if ( cl . stats [ r_refdef . currentplayernum ] [ STAT_HEALTH ] < = 0 )
return ;
memset ( & ent , 0 , sizeof ( ent ) ) ;
ent . model = cl . viewent [ r_refdef . currentplayernum ] . model ;
if ( ! ent . model )
return ;
# ifdef PEXT_SCALE
ent . scale = 1 ;
# endif
if ( r_drawviewmodel . value > 0 & & r_drawviewmodel . value < 1 )
ent . alpha = r_drawviewmodel . value ;
else
ent . alpha = 1 ;
ent . frame = cl . viewent [ r_refdef . currentplayernum ] . frame ;
ent . oldframe = oldframe [ r_refdef . currentplayernum ] ;
if ( ent . frame ! = prevframe [ r_refdef . currentplayernum ] )
{
oldframe [ r_refdef . currentplayernum ] = ent . oldframe = prevframe [ r_refdef . currentplayernum ] ;
lerptime [ r_refdef . currentplayernum ] = realtime ;
}
prevframe [ r_refdef . currentplayernum ] = ent . frame ;
if ( ent . model ! = oldmodel [ r_refdef . currentplayernum ] )
{
oldmodel [ r_refdef . currentplayernum ] = ent . model ;
oldframe [ r_refdef . currentplayernum ] = ent . oldframe = ent . frame ;
lerptime [ r_refdef . currentplayernum ] = realtime ;
}
2005-04-18 17:12:18 +00:00
ent . lerpfrac = 1 - ( realtime - lerptime [ r_refdef . currentplayernum ] ) * 10 ;
if ( ent . lerpfrac < 0 ) ent . lerpfrac = 0 ;
if ( ent . lerpfrac > 1 ) ent . lerpfrac = 1 ;
2005-02-12 18:56:04 +00:00
# define Q2RF_VIEWERMODEL 2 // don't draw through eyes, only mirrors
# define Q2RF_WEAPONMODEL 4 // only draw through eyes
# define Q2RF_DEPTHHACK 16 // for view weapon Z crunching
ent . flags = Q2RF_WEAPONMODEL | Q2RF_DEPTHHACK ;
V_AddEntity ( & ent ) ;
2005-04-16 16:21:27 +00:00
if ( ! v_powerupshell . value )
return ;
if ( cl . stats [ r_refdef . currentplayernum ] [ STAT_ITEMS ] & IT_QUAD )
2005-12-08 18:42:08 +00:00
{
2005-12-09 23:30:50 +00:00
# ifdef Q3SHADERS
2005-12-08 18:42:08 +00:00
if ( v_powerupshell . value = = 2 )
{
ent . forcedshader = R_RegisterCustom ( " powerups/quadWeapon " , Shader_DefaultSkinShell ) ;
V_AddEntity ( & ent ) ;
}
else
2005-12-09 23:30:50 +00:00
# endif
2005-12-08 18:42:08 +00:00
ent . flags | = Q2RF_SHELL_BLUE ;
}
2005-04-26 16:04:12 +00:00
if ( cl . stats [ r_refdef . currentplayernum ] [ STAT_ITEMS ] & IT_INVULNERABILITY )
2005-12-08 18:42:08 +00:00
{
2005-12-09 23:30:50 +00:00
# ifdef Q3SHADERS
2005-12-08 18:42:08 +00:00
if ( v_powerupshell . value = = 2 )
{
ent . forcedshader = R_RegisterCustom ( " powerups/regen " , Shader_DefaultSkinShell ) ;
ent . fatness = - 2.5 ;
V_AddEntity ( & ent ) ;
}
else
2005-12-09 23:30:50 +00:00
# endif
2005-12-08 18:42:08 +00:00
ent . flags | = Q2RF_SHELL_RED ;
}
2005-04-16 16:21:27 +00:00
if ( ! ( ent . flags & ( Q2RF_SHELL_RED | Q2RF_SHELL_GREEN | Q2RF_SHELL_BLUE ) ) )
return ;
ent . fatness = 0.5 ;
ent . alpha * = 0.1 ;
# ifdef Q3SHADERS //fixme: do better.
//fixme: this is woefully gl specific. :(
if ( qrenderer = = QR_OPENGL )
{
extern void Shader_DefaultSkinShell ( char * shortname , shader_t * s ) ;
ent . shaderRGBA [ 0 ] = ( ! ! ( ent . flags & Q2RF_SHELL_RED ) ) * 255 ;
ent . shaderRGBA [ 1 ] = ( ! ! ( ent . flags & Q2RF_SHELL_GREEN ) ) * 255 ;
ent . shaderRGBA [ 2 ] = ( ! ! ( ent . flags & Q2RF_SHELL_BLUE ) ) * 255 ;
ent . shaderRGBA [ 3 ] = ent . alpha * 255 ;
ent . forcedshader = R_RegisterCustom ( " q2/shell " , Shader_DefaultSkinShell ) ;
}
# endif
V_AddEntity ( & ent ) ;
2005-02-12 18:56:04 +00:00
}
2004-08-23 00:15:46 +00:00
//======================================================================
/*
= = = = = = = = = = = = = = =
CL_SetSolid
Builds all the pmove physents for the current frame
= = = = = = = = = = = = = = =
*/
void CL_SetSolidEntities ( void )
{
int i ;
frame_t * frame ;
packet_entities_t * pak ;
entity_state_t * state ;
pmove . physents [ 0 ] . model = cl . worldmodel ;
VectorCopy ( vec3_origin , pmove . physents [ 0 ] . origin ) ;
pmove . physents [ 0 ] . info = 0 ;
pmove . numphysent = 1 ;
frame = & cl . frames [ parsecountmod ] ;
pak = & frame - > packet_entities ;
for ( i = 0 ; i < pak - > num_entities ; i + + )
{
state = & pak - > entities [ i ] ;
2004-11-27 08:16:25 +00:00
if ( state - > modelindex < 0 )
2004-08-23 00:15:46 +00:00
continue ;
if ( ! cl . model_precache [ state - > modelindex ] )
continue ;
if ( * cl . model_precache [ state - > modelindex ] - > name = = ' * ' | | cl . model_precache [ state - > modelindex ] - > numsubmodels )
2005-02-06 02:47:36 +00:00
if ( cl . model_precache [ state - > modelindex ] - > hulls [ 1 ] . firstclipnode
2004-08-23 00:15:46 +00:00
| | cl . model_precache [ state - > modelindex ] - > clipbox )
{
pmove . physents [ pmove . numphysent ] . model = cl . model_precache [ state - > modelindex ] ;
VectorCopy ( state - > origin , pmove . physents [ pmove . numphysent ] . origin ) ;
VectorCopy ( state - > angles , pmove . physents [ pmove . numphysent ] . angles ) ;
2004-09-20 23:25:38 +00:00
pmove . physents [ pmove . numphysent ] . angles [ 0 ] * = - 1 ;
2004-08-23 00:15:46 +00:00
if ( + + pmove . numphysent = = MAX_PHYSENTS )
break ;
}
}
}
/*
= = =
Calculate the new position of players , without other player clipping
We do this to set up real player prediction .
Players are predicted twice , first without clipping other players ,
then with clipping against them .
This sets up the first phase .
= = =
*/
void CL_SetUpPlayerPrediction ( qboolean dopred )
{
int j ;
player_state_t * state ;
player_state_t exact ;
double playertime ;
int msec ;
frame_t * frame ;
struct predicted_player * pplayer ;
extern cvar_t cl_nopred ;
playertime = realtime - cls . latency + 0.02 ;
if ( playertime > realtime )
playertime = realtime ;
2004-12-15 17:47:42 +00:00
if ( cl_nopred . value | | cls . demoplayback )
2004-08-23 00:15:46 +00:00
return ;
frame = & cl . frames [ cl . parsecount & UPDATE_MASK ] ;
2005-02-06 02:47:36 +00:00
for ( j = 0 , pplayer = predicted_players , state = frame - > playerstate ;
2004-08-23 00:15:46 +00:00
j < MAX_CLIENTS ;
2004-10-04 07:26:16 +00:00
j + + , pplayer + + , state + + )
{
2004-08-23 00:15:46 +00:00
pplayer - > active = false ;
if ( state - > messagenum ! = cl . parsecount )
continue ; // not present this frame
if ( ! state - > modelindex )
continue ;
pplayer - > active = true ;
pplayer - > flags = state - > flags ;
if ( pplayer - > frame ! = state - > frame )
{
state - > oldframe = pplayer - > oldframe = pplayer - > frame ;
state - > lerpstarttime = pplayer - > lerptime = realtime ;
pplayer - > frame = state - > frame ;
}
else
{
state - > lerpstarttime = pplayer - > lerptime ;
state - > oldframe = pplayer - > oldframe ;
}
// note that the local player is special, since he moves locally
// we use his last predicted postition
2004-10-04 07:26:16 +00:00
if ( j = = cl . playernum [ 0 ] )
{
2004-08-23 00:15:46 +00:00
VectorCopy ( cl . frames [ cls . netchan . outgoing_sequence & UPDATE_MASK ] . playerstate [ cl . playernum [ 0 ] ] . origin ,
pplayer - > origin ) ;
2004-10-04 07:26:16 +00:00
}
else
{
2004-08-23 00:15:46 +00:00
// only predict half the move to minimize overruns
msec = 500 * ( playertime - state - > state_time ) ;
if ( msec < = 0 | |
( ! cl_predict_players . value & & ! cl_predict_players2 . value ) | |
! dopred )
{
VectorCopy ( state - > origin , pplayer - > origin ) ;
//Con_DPrintf ("nopredict\n");
}
else
{
// predict players movement
if ( msec > 255 )
msec = 255 ;
state - > command . msec = msec ;
//Con_DPrintf ("predict: %i\n", msec);
CL_PredictUsercmd ( 0 , state , & exact , & state - > command ) ;
VectorCopy ( exact . origin , pplayer - > origin ) ;
}
2004-10-04 07:26:16 +00:00
if ( cl . spectator )
{
if ( ! Cam_DrawPlayer ( 0 , j ) )
VectorCopy ( pplayer - > origin , cl . simorg [ 0 ] ) ;
2005-02-06 02:47:36 +00:00
2004-10-04 07:26:16 +00:00
}
2004-08-23 00:15:46 +00:00
}
}
}
/*
= = = = = = = = = = = = = = =
CL_SetSolid
Builds all the pmove physents for the current frame
Note that CL_SetUpPlayerPrediction ( ) must be called first !
pmove must be setup with world and solid entity hulls before calling
( via CL_PredictMove )
= = = = = = = = = = = = = = =
*/
void CL_SetSolidPlayers ( int playernum )
{
int j ;
extern vec3_t player_mins ;
extern vec3_t player_maxs ;
struct predicted_player * pplayer ;
physent_t * pent ;
if ( ! cl_solid_players . value )
return ;
pent = pmove . physents + pmove . numphysent ;
if ( pmove . numphysent = = MAX_PHYSENTS ) //too many.
return ;
for ( j = 0 , pplayer = predicted_players ; j < MAX_CLIENTS ; j + + , pplayer + + ) {
if ( ! pplayer - > active )
continue ; // not present this frame
// the player object never gets added
if ( j = = playernum )
continue ;
if ( pplayer - > flags & PF_DEAD )
continue ; // dead players aren't solid
pent - > model = 0 ;
VectorCopy ( pplayer - > origin , pent - > origin ) ;
pent - > angles [ 0 ] = pent - > angles [ 1 ] = pent - > angles [ 2 ] = 0 ; //don't bother rotating - only useful with bsps
VectorCopy ( player_mins , pent - > mins ) ;
VectorCopy ( player_maxs , pent - > maxs ) ;
if ( + + pmove . numphysent = = MAX_PHYSENTS ) //we just hit 88 miles per hour.
break ;
pent + + ;
}
}
/*
= = = = = = = = = = = = = = =
CL_EmitEntities
Builds the visedicts array for cl . time
Made up of : clients , packet_entities , nails , and tents
= = = = = = = = = = = = = = =
*/
2005-02-12 18:56:04 +00:00
void CL_SwapEntityLists ( void )
{
cl_oldnumvisedicts = cl_numvisedicts ;
cl_oldvisedicts = cl_visedicts ;
if ( cl_visedicts = = cl_visedicts_list [ 0 ] )
cl_visedicts = cl_visedicts_list [ 1 ] ;
else
cl_visedicts = cl_visedicts_list [ 0 ] ;
// cl_oldvisedicts = cl_visedicts_list[(cls.netchan.incoming_sequence-1)&1];
// cl_visedicts = cl_visedicts_list[cls.netchan.incoming_sequence&1];
cl_numvisedicts = 0 ;
}
2004-08-23 00:15:46 +00:00
void CL_EmitEntities ( void )
{
if ( cls . state ! = ca_active )
return ;
2004-11-27 08:16:25 +00:00
CL_DecayLights ( ) ;
2004-08-23 00:15:46 +00:00
# ifdef Q2CLIENT
2005-05-26 12:55:34 +00:00
if ( cls . protocol = = CP_QUAKE2 )
2004-08-23 00:15:46 +00:00
{
CLQ2_AddEntities ( ) ;
return ;
}
# endif
if ( ! cl . validsequence )
return ;
2005-02-12 18:56:04 +00:00
CL_SwapEntityLists ( ) ;
2004-08-23 00:15:46 +00:00
CL_LinkPlayers ( ) ;
CL_LinkPacketEntities ( ) ;
CL_LinkProjectiles ( ) ;
CL_UpdateTEnts ( ) ;
2005-04-16 16:21:27 +00:00
CL_LinkViewModel ( ) ;
2004-08-23 00:15:46 +00:00
}
2004-12-08 04:14:52 +00:00
void CL_ParseClientdata ( void ) ;
2004-12-15 17:47:42 +00:00
/*
2004-08-23 00:15:46 +00:00
void MVD_Interpolate ( void )
{
2004-12-08 04:14:52 +00:00
player_state_t * self , * oldself ;
CL_ParseClientdata ( ) ;
self = & cl . frames [ cl . parsecount & UPDATE_MASK ] . playerstate [ cl . playernum [ 0 ] ] ;
oldself = & cl . frames [ ( cls . netchan . outgoing_sequence - 1 ) & UPDATE_MASK ] . playerstate [ cl . playernum [ 0 ] ] ;
self - > messagenum = cl . parsecount ;
VectorCopy ( oldself - > origin , self - > origin ) ;
VectorCopy ( oldself - > velocity , self - > velocity ) ;
VectorCopy ( oldself - > viewangles , self - > viewangles ) ;
2005-02-06 02:47:36 +00:00
2004-08-23 00:15:46 +00:00
cls . netchan . outgoing_sequence = cl . parsecount + 1 ;
}
2004-12-15 17:47:42 +00:00
*/
2004-08-23 00:15:46 +00:00
int mvd_fixangle ;
static float MVD_AdjustAngle ( float current , float ideal , float fraction ) {
float move ;
move = ideal - current ;
if ( move > = 180 )
move - = 360 ;
else if ( move < = - 180 )
move + = 360 ;
return current + fraction * move ;
}
2004-12-15 17:47:42 +00:00
extern float nextdemotime ;
extern float olddemotime ;
static void MVD_InitInterpolation ( void )
{
2004-08-23 00:15:46 +00:00
player_state_t * state , * oldstate ;
int i , tracknum ;
frame_t * frame , * oldframe ;
vec3_t dist ;
struct predicted_player * pplayer ;
2004-12-15 17:47:42 +00:00
# define ISDEAD(i) ( (i) >= 41 && (i) <= 102 )
2004-08-23 00:15:46 +00:00
if ( ! cl . validsequence )
return ;
// if (nextdemotime <= olddemotime)
// return;
frame = & cl . frames [ cl . parsecount & UPDATE_MASK ] ;
oldframe = & cl . frames [ ( cl . parsecount - 1 ) & UPDATE_MASK ] ;
// clients
2004-12-15 17:47:42 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2004-08-23 00:15:46 +00:00
pplayer = & predicted_players [ i ] ;
state = & frame - > playerstate [ i ] ;
oldstate = & oldframe - > playerstate [ i ] ;
2004-12-15 17:47:42 +00:00
if ( pplayer - > predict )
{
2004-08-23 00:15:46 +00:00
VectorCopy ( pplayer - > oldo , oldstate - > origin ) ;
VectorCopy ( pplayer - > olda , oldstate - > command . angles ) ;
VectorCopy ( pplayer - > oldv , oldstate - > velocity ) ;
}
pplayer - > predict = false ;
2004-12-15 17:47:42 +00:00
tracknum = spec_track [ 0 ] ;
if ( ( mvd_fixangle & 1 ) < < i )
{
if ( i = = tracknum )
{
state - > command . angles [ 0 ] = ( state - > viewangles [ 0 ] = cl . viewangles [ 0 ] [ 0 ] ) * 65535 / 360 ;
state - > command . angles [ 1 ] = ( state - > viewangles [ 1 ] = cl . viewangles [ 0 ] [ 1 ] ) * 65535 / 360 ;
state - > command . angles [ 2 ] = ( state - > viewangles [ 2 ] = cl . viewangles [ 0 ] [ 2 ] ) * 65535 / 360 ;
2004-08-23 00:15:46 +00:00
}
// no angle interpolation
VectorCopy ( state - > command . angles , oldstate - > command . angles ) ;
mvd_fixangle & = ~ ( 1 < < i ) ;
}
// we dont interpolate ourself if we are spectating
2004-12-15 17:47:42 +00:00
if ( i = = cl . playernum [ 0 ] & & cl . spectator )
2004-08-23 00:15:46 +00:00
continue ;
memset ( state - > velocity , 0 , sizeof ( state - > velocity ) ) ;
if ( state - > messagenum ! = cl . parsecount )
continue ; // not present this frame
if ( oldstate - > messagenum ! = cl . oldparsecount | | ! oldstate - > messagenum )
continue ; // not present last frame
if ( ! ISDEAD ( state - > frame ) & & ISDEAD ( oldstate - > frame ) )
continue ;
VectorSubtract ( state - > origin , oldstate - > origin , dist ) ;
if ( DotProduct ( dist , dist ) > 22500 )
continue ;
VectorScale ( dist , 1 / ( nextdemotime - olddemotime ) , pplayer - > oldv ) ;
VectorCopy ( state - > origin , pplayer - > oldo ) ;
VectorCopy ( state - > command . angles , pplayer - > olda ) ;
pplayer - > oldstate = oldstate ;
pplayer - > predict = true ;
}
2004-12-15 17:47:42 +00:00
/*
2004-08-23 00:15:46 +00:00
// nails
2004-12-15 17:47:42 +00:00
for ( i = 0 ; i < cl_num_projectiles ; i + + )
{
2004-08-23 00:15:46 +00:00
if ( ! cl . int_projectiles [ i ] . interpolate )
continue ;
VectorCopy ( cl . int_projectiles [ i ] . origin , cl_projectiles [ i ] . origin ) ;
}
2004-12-15 17:47:42 +00:00
*/
2004-08-23 00:15:46 +00:00
}
void MVD_Interpolate ( void )
{
int i , j ;
float f ;
frame_t * frame , * oldframe ;
player_state_t * state , * oldstate , * self , * oldself ;
entity_state_t * oldents ;
struct predicted_player * pplayer ;
static float old ;
2005-12-21 03:07:33 +00:00
extern float demtime ;
2004-08-23 00:15:46 +00:00
2004-12-15 17:47:42 +00:00
self = & cl . frames [ cl . parsecount & UPDATE_MASK ] . playerstate [ cl . playernum [ 0 ] ] ;
oldself = & cl . frames [ ( cls . netchan . outgoing_sequence - 1 ) & UPDATE_MASK ] . playerstate [ cl . playernum [ 0 ] ] ;
2004-08-23 00:15:46 +00:00
self - > messagenum = cl . parsecount ;
VectorCopy ( oldself - > origin , self - > origin ) ;
VectorCopy ( oldself - > velocity , self - > velocity ) ;
VectorCopy ( oldself - > viewangles , self - > viewangles ) ;
2004-12-15 17:47:42 +00:00
if ( old ! = nextdemotime )
{
2004-08-23 00:15:46 +00:00
old = nextdemotime ;
MVD_InitInterpolation ( ) ;
}
CL_ParseClientdata ( ) ;
cls . netchan . outgoing_sequence = cl . parsecount + 1 ;
if ( ! cl . validsequence )
return ;
if ( nextdemotime < = olddemotime )
return ;
frame = & cl . frames [ cl . parsecount & UPDATE_MASK ] ;
oldframe = & cl . frames [ cl . oldparsecount & UPDATE_MASK ] ;
oldents = oldframe - > packet_entities . entities ;
2005-12-21 03:07:33 +00:00
f = ( demtime - olddemotime ) / ( nextdemotime - olddemotime ) ;
2004-12-15 17:47:42 +00:00
if ( f < 0 )
f = 0 ;
if ( f > 1 )
f = 1 ;
2004-08-23 00:15:46 +00:00
// interpolate nails
2004-12-15 17:47:42 +00:00
/* for (i = 0; i < cl_num_projectiles; i++)
{
2004-08-23 00:15:46 +00:00
if ( ! cl . int_projectiles [ i ] . interpolate )
continue ;
2004-12-15 17:47:42 +00:00
for ( j = 0 ; j < 3 ; j + + )
{
2004-08-23 00:15:46 +00:00
cl_projectiles [ i ] . origin [ j ] = cl_oldprojectiles [ cl . int_projectiles [ i ] . oldindex ] . origin [ j ] +
f * ( cl . int_projectiles [ i ] . origin [ j ] - cl_oldprojectiles [ cl . int_projectiles [ i ] . oldindex ] . origin [ j ] ) ;
}
}
2004-12-15 17:47:42 +00:00
*/
2004-08-23 00:15:46 +00:00
// interpolate clients
2004-12-15 17:47:42 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2004-08-23 00:15:46 +00:00
pplayer = & predicted_players [ i ] ;
state = & frame - > playerstate [ i ] ;
oldstate = & oldframe - > playerstate [ i ] ;
2004-12-15 17:47:42 +00:00
if ( pplayer - > predict )
{
for ( j = 0 ; j < 3 ; j + + )
{
state - > viewangles [ j ] = MVD_AdjustAngle ( oldstate - > command . angles [ j ] / 65535.0f * 360 , pplayer - > olda [ j ] / 65535.0f * 360 , f ) ;
2004-08-23 00:15:46 +00:00
state - > origin [ j ] = oldstate - > origin [ j ] + f * ( pplayer - > oldo [ j ] - oldstate - > origin [ j ] ) ;
state - > velocity [ j ] = oldstate - > velocity [ j ] + f * ( pplayer - > oldv [ j ] - oldstate - > velocity [ j ] ) ;
}
}
}
}
2004-12-15 17:47:42 +00:00
void CL_ClearPredict ( void )
{
2004-08-23 00:15:46 +00:00
memset ( predicted_players , 0 , sizeof ( predicted_players ) ) ;
mvd_fixangle = 0 ;
}