Ejemplo n.º 1
0
/*
=============
CL_ParseReliableEvent

=============
*/
void CL_ParseReliableEvent( sizebuf_t *msg )
{
	int		event_index;
	event_args_t	nullargs, args;
	float		delay = 0.0f;
	cl_entity_t	*pEnt;

	Q_memset( &nullargs, 0, sizeof( nullargs ));

	event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS );

	if( BF_ReadOneBit( msg ))
		delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f);

	// reliable events not use delta-compression just null-compression
	MSG_ReadDeltaEvent( msg, &nullargs, &args );

	if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL )
	{
		if( VectorIsNull( args.origin ))
			VectorCopy( pEnt->curstate.origin, args.origin );
		if( VectorIsNull( args.angles ))
			VectorCopy( pEnt->curstate.angles, args.angles );
		if( VectorIsNull( args.velocity ))
			VectorCopy( pEnt->curstate.velocity, args.velocity );
	}

	CL_QueueEvent( FEV_RELIABLE|FEV_SERVER, event_index, delay, &args );
}
Ejemplo n.º 2
0
/*
===============
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;
	cl_entity_t	*ent;
	physent_t		*pe;

	if( !cl_solid_players->integer )
		return;

	for( j = 0; j < cl.maxclients; j++ )
	{
		// the player object never gets added
		if( j == playernum ) continue;

		ent = CL_GetEntityByIndex( j + 1 );		

		if( !ent || !ent->player )
			continue; // not present this frame

		pe = &clgame.pmove->physents[clgame.pmove->numphysent];
		if( CL_CopyEntityToPhysEnt( pe, ent ))
			clgame.pmove->numphysent++;
	}
}
Ejemplo n.º 3
0
/*
===============
CL_AddPacketEntities

===============
*/
void CL_AddPacketEntities( frame_t *frame )
{
	cl_entity_t	*ent, *clent;
	int		i, e, entityType;

	clent = CL_GetLocalPlayer();
	if( !clent ) return;

	for( i = 0; i < cl.frame.num_entities; i++ )
	{
		e = cls.packet_entities[(cl.frame.first_entity + i) % cls.num_client_entities].number;
		ent = CL_GetEntityByIndex( e );

		if( !ent || ent == clgame.entities )
			continue;

		CL_UpdateEntityFields( ent );

		if( ent->player ) entityType = ET_PLAYER;
		else if( ent->curstate.entityType == ENTITY_BEAM )
			entityType = ET_BEAM;
		else entityType = ET_NORMAL;

		CL_AddVisibleEntity( ent, entityType );
	}
}
Ejemplo n.º 4
0
/*
=============
CL_GetWaterEntity

returns water brush where inside pos
=============
*/
cl_entity_t *CL_GetWaterEntity( const float *rgflPos )
{
	int	entnum;

	entnum = CL_WaterEntity( rgflPos );
	if( entnum <= 0 ) return NULL; // world or not water

	return CL_GetEntityByIndex( entnum );
}
Ejemplo n.º 5
0
/*
====================
CL_AddLinksToPmove

collect solid entities
====================
*/
void CL_AddLinksToPmove()
{
	cl_entity_t	*check;
	physent_t		*pe;
	int		i, solid, idx;

	for( i = 0; i < cl.frame.num_entities; i++ )
	{
		idx = cls.packet_entities[(cl.frame.first_entity + i) % cls.num_client_entities].number;
		check = CL_GetEntityByIndex( idx );

		// don't add the world and clients here
		if( !check || check == &clgame.entities[0] )
			continue;

		if( clgame.pmove->numvisent < MAX_PHYSENTS )
		{
			pe = &clgame.pmove->visents[clgame.pmove->numvisent];
			if( CL_CopyEntityToPhysEnt( pe, check ))
				clgame.pmove->numvisent++;
		}

		// players will be added later
		if( check->player )
			continue;

		// can't collide with zeroed hull
		if( VectorIsNull( check->curstate.mins ) && VectorIsNull( check->curstate.maxs ))
			continue;

		solid = check->curstate.solid;

		if( solid == SOLID_BSP || solid == SOLID_BBOX || solid == SOLID_SLIDEBOX || solid == SOLID_CUSTOM )
		{
			// reserve slots for all the clients
			if( clgame.pmove->numphysent < ( MAX_PHYSENTS - cl.maxclients ))
			{
				pe = &clgame.pmove->physents[clgame.pmove->numphysent];
				if( CL_CopyEntityToPhysEnt( pe, check ))
					clgame.pmove->numphysent++;
			}
		}
		else if( solid == SOLID_NOT && check->curstate.skin != CONTENTS_NONE )
		{
			if( clgame.pmove->nummoveent < MAX_MOVEENTS )
			{
				pe = &clgame.pmove->moveents[clgame.pmove->nummoveent];
				if( CL_CopyEntityToPhysEnt( pe, check ))
					clgame.pmove->nummoveent++;
			}
		}
	}
}
Ejemplo n.º 6
0
static void pfnPlaybackEventFull( int flags, int clientindex, word eventindex, float delay, float *origin,
	float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
{
	cl_entity_t	*ent;

	ent = CL_GetEntityByIndex( clientindex + 1 );
	if( ent == NULL ) return;

	CL_PlaybackEvent( flags, (edict_t *)ent, eventindex,
		delay, origin, angles,
		fparam1, fparam2,
		iparam1, iparam2,
		bparam1, bparam2 );
}
Ejemplo n.º 7
0
void SND_CloseMouth( channel_t *ch )
{
    if( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_STREAM )
    {
        cl_entity_t	*clientEntity;

        clientEntity = CL_GetEntityByIndex( ch->entnum );

        if( clientEntity )
        {
            // shut mouth
            clientEntity->mouth.mouthopen = 0;
        }
    }
}
Ejemplo n.º 8
0
void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count )
{
    cl_entity_t	*clientEntity;
    char		*pdata = NULL;
    mouth_t		*pMouth = NULL;
    int		savg, data;
    int		scount, pos = 0;
    uint 		i;

    clientEntity = CL_GetEntityByIndex( ch->entnum );
    if( !clientEntity ) return;

    pMouth = &clientEntity->mouth;

    if( ch->isSentence )
    {
        if( ch->currentWord )
            pos = ch->currentWord->sample;
    }
    else pos = ch->pMixer.sample;

    count = S_GetOutputData( pSource, &pdata, pos, count, ch->use_loop );
    if( pdata == NULL ) return;

    i = 0;
    scount = pMouth->sndcount;
    savg = 0;

    while( i < count && scount < CAVGSAMPLES )
    {
        data = pdata[i];
        savg += abs( data );

        i += 80 + ((byte)data & 0x1F);
        scount++;
    }

    pMouth->sndavg += savg;
    pMouth->sndcount = (byte)scount;

    if( pMouth->sndcount >= CAVGSAMPLES )
    {
        pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;
        pMouth->sndavg = 0;
        pMouth->sndcount = 0;
    }
}
Ejemplo n.º 9
0
/*
==============
CL_ParseStudioDecal

Studio Decal message. Used by engine in case
we need save\restore decals
==============
*/
void CL_ParseStudioDecal( sizebuf_t *msg )
{
	modelstate_t	state;
	vec3_t		start, pos;
	int		decalIndex, entityIndex;
	int		modelIndex = 0;
	int		flags;

	pos[0] = BF_ReadCoord( msg );
	pos[1] = BF_ReadCoord( msg );
	pos[2] = BF_ReadCoord( msg );
	start[0] = BF_ReadCoord( msg );
	start[1] = BF_ReadCoord( msg );
	start[2] = BF_ReadCoord( msg );
	decalIndex = BF_ReadShort( msg );
	entityIndex = BF_ReadShort( msg );
	flags = BF_ReadByte( msg );

	state.sequence = BF_ReadShort( msg );
	state.frame = BF_ReadShort( msg );
	state.blending[0] = BF_ReadByte( msg );
	state.blending[1] = BF_ReadByte( msg );
	state.controller[0] = BF_ReadByte( msg );
	state.controller[1] = BF_ReadByte( msg );
	state.controller[2] = BF_ReadByte( msg );
	state.controller[3] = BF_ReadByte( msg );

	if( cls.state == ca_connected )
	{
		// this message came on restore.
		// read modelindex in case client models are not linked with entities
		// because first client frame has not yet received
		modelIndex = BF_ReadShort( msg );
	}

	if( clgame.drawFuncs.R_StudioDecalShoot )
	{
		int decalTexture = CL_DecalIndex( decalIndex );
		cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );

		if( ent && !ent->model && modelIndex != 0 )
			ent->model = Mod_Handle( modelIndex );

		clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
	}
}
Ejemplo n.º 10
0
void SND_InitMouth( int entnum, int entchannel )
{
    if(( entchannel == CHAN_VOICE || entchannel == CHAN_STREAM ) && entnum > 0 )
    {
        cl_entity_t	*clientEntity;

        // init mouth movement vars
        clientEntity = CL_GetEntityByIndex( entnum );

        if( clientEntity )
        {
            clientEntity->mouth.mouthopen = 0;
            clientEntity->mouth.sndavg = 0;
            clientEntity->mouth.sndcount = 0;
        }
    }
}
Ejemplo n.º 11
0
//
// sound engine implementation
//
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, float *pradius )
{
	cl_entity_t	*ent;
	qboolean		valid_origin;

	ASSERT( origin != NULL );

	if( entnum == 0 ) return true; // static sound

	if(( entnum - 1 ) == cl.playernum )
	{
		VectorCopy( cl.frame.local.client.origin, origin );
		return true;
	}

	valid_origin = VectorIsNull( origin ) ? false : true;          
	ent = CL_GetEntityByIndex( entnum );

	// entity is not present on the client but has valid origin
	if( !ent || !ent->index ) return valid_origin;

	if( ent->curstate.messagenum == 0 )
	{
		// entity is never has updates on the client
		// so we should use static origin instead
		return valid_origin;
	}
#if 0
	// uncomment this if you want enable additional check by PVS
	if( ent->curstate.messagenum != cl.parsecount )
		return valid_origin;
#endif
	// setup origin
	VectorAverage( ent->curstate.mins, ent->curstate.maxs, origin );
	VectorAdd( origin, ent->curstate.origin, origin );

	// setup radius
	if( pradius )
	{
		if( ent->model != NULL && ent->model->radius ) *pradius = ent->model->radius;
		else *pradius = RadiusFromBounds( ent->curstate.mins, ent->curstate.maxs );
	}

	return true;
}
Ejemplo n.º 12
0
/*
===============
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;
    cl_entity_t	   *ent;
    entity_state_t *state;
    physent_t      *pe;

    if( !cl_solid_players->integer )
        return;

    for( j = 0; j < cl.maxclients; j++ )
    {
        // the player object never gets added
        if( j == playernum )
            continue;

        ent = CL_GetEntityByIndex( j + 1 );

        if( !ent || !ent->player )
            continue; // not present this frame


#if 1 // came from SetUpPlayerPrediction
        state = cl.frames[cl.parsecountmod].playerstate + j;

        if( ent->curstate.messagenum != cl.parsecount )
            continue; // not present this frame [2]

        if( ent->curstate.movetype == MOVETYPE_NONE )
            continue;

        if( state->effects & EF_NODRAW )
            continue; // skip invisible

        if( !state->solid )
            continue; // not solid

#endif

        pe = &clgame.pmove->physents[clgame.pmove->numphysent];
        if( CL_CopyEntityToPhysEnt( pe, ent ))
            clgame.pmove->numphysent++;
    }
}
Ejemplo n.º 13
0
/*
==============
CL_ParseStudioDecal

Studio Decal message. Used by engine in case
we need save\restore decals
==============
*/
void CL_ParseStudioDecal( sizebuf_t *msg )
{
	modelstate_t	state;
	vec3_t		start, pos;
	int		decalIndex, entityIndex;
	int		modelIndex = 0;
	int		flags;

	BF_ReadVec3Coord( msg, pos );
	BF_ReadVec3Coord( msg, start );
	decalIndex = BF_ReadWord( msg );
	entityIndex = BF_ReadWord( msg );
	flags = BF_ReadByte( msg );

	state.sequence = BF_ReadShort( msg );
	state.frame = BF_ReadShort( msg );
	state.blending[0] = BF_ReadByte( msg );
	state.blending[1] = BF_ReadByte( msg );
	state.controller[0] = BF_ReadByte( msg );
	state.controller[1] = BF_ReadByte( msg );
	state.controller[2] = BF_ReadByte( msg );
	state.controller[3] = BF_ReadByte( msg );
	modelIndex = BF_ReadWord( msg );
	state.body = BF_ReadByte( msg );
	state.skin = BF_ReadByte( msg );

	if( clgame.drawFuncs.R_StudioDecalShoot != NULL )
	{
		int decalTexture = CL_DecalIndex( decalIndex );
		cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );

		if( ent && !ent->model && modelIndex != 0 )
			ent->model = Mod_Handle( modelIndex );

		clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
	}
}
Ejemplo n.º 14
0
/*
==================
CL_ParsePacketEntities

An svc_packetentities has just been parsed, deal with the
rest of the data stream.
==================
*/
void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
{
	frame_t		*newframe, *oldframe;
	int		oldindex, newnum, oldnum;
	int		oldpacket, newpacket;
	cl_entity_t	*player;
	entity_state_t	*oldent;
	int		i, count;

	// save first uncompressed packet as timestamp
	if( cls.changelevel && !delta && cls.demorecording )
		CL_WriteDemoJumpTime();

	// first, allocate packet for new frame
	count = BF_ReadWord( msg );

	newpacket = cl.parsecountmod;
	newframe = &cl.frames[newpacket];

	// allocate parse entities
	newframe->first_entity = cls.next_client_entities;
	newframe->num_entities = 0;
	newframe->valid = true; // assume valid

	if( delta )
	{
		int	subtracted;

		oldpacket = BF_ReadByte( msg );
		subtracted = ((( cls.netchan.incoming_sequence & 0xFF ) - oldpacket ) & 0xFF );

		if( subtracted == 0 )
		{
			Host_Error( "CL_DeltaPacketEntities: update too old, connection dropped.\n" );
			return;
		}

		if( subtracted >= CL_UPDATE_MASK )
		{	
			// we can't use this, it is too old
			Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
			CL_FlushEntityPacket( msg );
			return;
		}

		oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK];

		if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - 128 ))
		{
			Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
			CL_FlushEntityPacket( msg );
			return;
		}
	}
	else
	{
		// this is a full update that we can start delta compressing from now
		oldframe = NULL;
		oldpacket = -1;		// delta too old or is initial message
		cl.force_send_usercmd = true;	// send reply
		cls.demowaiting = false;	// we can start recording now
	}

	// mark current delta state
	cl.validsequence = cls.netchan.incoming_sequence;

	oldent = NULL;
	oldindex = 0;

	if( !oldframe )
	{
		oldnum = MAX_ENTNUMBER;
	}
	else
	{
		if( oldindex >= oldframe->num_entities )
		{
			oldnum = MAX_ENTNUMBER;
		}
		else
		{
			oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
			oldnum = oldent->number;
		}
	}

	while( 1 )
	{
		newnum = BF_ReadWord( msg );
		if( !newnum ) break; // end of packet entities

		if( BF_CheckOverflow( msg ))
			Host_Error( "CL_ParsePacketEntities: read overflow\n" );

		while( oldnum < newnum )
		{	
			// one or more entities from the old packet are unchanged
			CL_DeltaEntity( msg, newframe, oldnum, oldent, true );
			
			oldindex++;

			if( oldindex >= oldframe->num_entities )
			{
				oldnum = MAX_ENTNUMBER;
			}
			else
			{
				oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
				oldnum = oldent->number;
			}
		}

		if( oldnum == newnum )
		{	
			// delta from previous state
			CL_DeltaEntity( msg, newframe, newnum, oldent, false );
			oldindex++;

			if( oldindex >= oldframe->num_entities )
			{
				oldnum = MAX_ENTNUMBER;
			}
			else
			{
				oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
				oldnum = oldent->number;
			}
			continue;
		}

		if( oldnum > newnum )
		{	
			// delta from baseline ?
			CL_DeltaEntity( msg, newframe, newnum, NULL, false );
			continue;
		}
	}

	// any remaining entities in the old frame are copied over
	while( oldnum != MAX_ENTNUMBER )
	{	
		// one or more entities from the old packet are unchanged
		CL_DeltaEntity( msg, newframe, oldnum, oldent, true );
		oldindex++;

		if( oldindex >= oldframe->num_entities )
		{
			oldnum = MAX_ENTNUMBER;
		}
		else
		{
			oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
			oldnum = oldent->number;
		}
	}

	cl.frame = *newframe;

	if( !cl.frame.valid ) return;

	player = CL_GetLocalPlayer();
		
	if( cls.state != ca_active )
	{
		// client entered the game
		cls.state = ca_active;
		cl.force_refdef = true;
		cls.changelevel = false;		// changelevel is done
		cls.changedemo = false;		// changedemo is done

		SCR_MakeLevelShot();		// make levelshot if needs
		Cvar_SetFloat( "scr_loading", 0.0f );	// reset progress bar	

		if(( cls.demoplayback || cls.disable_servercount != cl.servercount ) && cl.video_prepped )
			SCR_EndLoadingPlaque(); // get rid of loading plaque
	}

	// update local player states
	clgame.dllFuncs.pfnTxferLocalOverrides( &player->curstate, &newframe->local.client );

	// update state for all players
	for( i = 0; i < cl.maxclients; i++ )
	{
		cl_entity_t *ent = CL_GetEntityByIndex( i + 1 );
		if( !ent ) continue;
		clgame.dllFuncs.pfnProcessPlayerState( &newframe->playerstate[i], &ent->curstate );
		newframe->playerstate[i].number = ent->index;
	}

	cl.frame = *newframe;
}
Ejemplo n.º 15
0
void CL_UpdateEntityFields( cl_entity_t *ent )
{
	// parametric rockets code
	if( ent->curstate.starttime != 0.0f && ent->curstate.impacttime != 0.0f )
	{
		float	lerp = ( cl.time - ent->curstate.starttime ) / ( ent->curstate.impacttime - ent->curstate.starttime );
		vec3_t	dir;

		lerp = bound( 0.0f, lerp, 1.0f );

		// first we need to calc actual origin
		VectorLerp( ent->curstate.startpos, lerp, ent->curstate.endpos, ent->curstate.origin );
		VectorSubtract( ent->curstate.endpos, ent->curstate.startpos, dir );
		VectorAngles( dir, ent->curstate.angles ); // re-aim projectile		
	}

	ent->model = Mod_Handle( ent->curstate.modelindex );
	ent->curstate.msg_time = cl.time;

	CL_InterpolateModel( ent );

	if( ent->player && RP_LOCALCLIENT( ent )) // stupid Half-Life bug
		ent->angles[PITCH] = -ent->angles[PITCH] / 3.0f;

	// make me lerp
	if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f )
	{
		float		d, f = 0.0f;
		int		i;

		// don't do it if the goalstarttime hasn't updated in a while.
		// NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
		// was increased to 1.0 s., which is 2x the max lag we are accounting for.
		if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime ))
			f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime );

		f = f - 1.0f;

		ent->origin[0] += ( ent->origin[0] - ent->latched.prevorigin[0] ) * f;
		ent->origin[1] += ( ent->origin[1] - ent->latched.prevorigin[1] ) * f;
		ent->origin[2] += ( ent->origin[2] - ent->latched.prevorigin[2] ) * f;

		for( i = 0; i < 3; i++ )
		{
			float	ang1, ang2;

			ang1 = ent->angles[i];
			ang2 = ent->latched.prevangles[i];
			d = ang1 - ang2;
			if( d > 180.0f ) d -= 360.0f;
			else if( d < -180.0f ) d += 360.0f;
			ent->angles[i] += d * f;
		}
	}
	else if( ent->curstate.eflags & EFLAG_SLERP )
	{
		float		d, f = 0.0f;
		cl_entity_t	*m_pGround = NULL;
		int		i;

		// don't do it if the goalstarttime hasn't updated in a while.
		// NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
		// was increased to 1.0 s., which is 2x the max lag we are accounting for.
		if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime ))
			f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime );

		f = f - 1.0f;

		if( ent->curstate.movetype == MOVETYPE_FLY )
		{
			ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f;
			ent->origin[1] += ( ent->curstate.origin[1] - ent->latched.prevorigin[1] ) * f;
			ent->origin[2] += ( ent->curstate.origin[2] - ent->latched.prevorigin[2] ) * f;

			for( i = 0; i < 3; i++ )
			{
				float	ang1, ang2;

				ang1 = ent->curstate.angles[i];
				ang2 = ent->latched.prevangles[i];
				d = ang1 - ang2;
				if( d > 180.0f ) d -= 360.0f;
				else if( d < -180.0f ) d += 360.0f;
				ent->angles[i] += d * f;
			}
		}
		else if( ent->curstate.movetype == MOVETYPE_STEP )
		{
			vec3_t	vecSrc, vecEnd;
			pmtrace_t	trace;

			if( ent->model )
			{
				CL_SetTraceHull( 0 ); // g-cont. player hull for better detect moving platforms
				VectorSet( vecSrc, ent->origin[0], ent->origin[1], ent->origin[2] + ent->model->maxs[2] );
				VectorSet( vecEnd, vecSrc[0], vecSrc[1], vecSrc[2] - ent->model->mins[2] - 8.0f );		
				CL_PlayerTraceExt( vecSrc, vecEnd, PM_STUDIO_IGNORE, CL_PushMoveFilter, &trace );
				m_pGround = CL_GetEntityByIndex( pfnIndexFromTrace( &trace ));
			}

			if( m_pGround && m_pGround->curstate.movetype == MOVETYPE_PUSH )
			{
				qboolean	applyVel, applyAvel;

				applyVel = !VectorCompare( m_pGround->curstate.origin, m_pGround->prevstate.origin );
				applyAvel = !VectorCompare( m_pGround->curstate.angles, m_pGround->prevstate.angles );

				if( applyVel || applyAvel )
				{
					ent->origin[0] += ( m_pGround->curstate.origin[0] - m_pGround->prevstate.origin[0] ) * -1.0f;
					ent->origin[1] += ( m_pGround->curstate.origin[1] - m_pGround->prevstate.origin[1] ) * -1.0f;
//					ent->origin[2] += ( m_pGround->curstate.origin[2] - m_pGround->prevstate.origin[2] ) * -1.0f;
					ent->latched.prevorigin[2] = ent->origin[2];
				}

				if( applyAvel )
				{
					for( i = 0; i < 3; i++ )
					{
						float	ang1, ang2;

						ang1 = m_pGround->curstate.angles[i];
						ang2 = m_pGround->prevstate.angles[i];
						d = ang1 - ang2;
						if( d > 180.0f ) d -= 360.0f;
						else if( d < -180.0f ) d += 360.0f;
						ent->angles[i] += d * -1.0f;
					}
				}
			}

			// moved code from StudioSetupTransform here
			if( host.features & ENGINE_COMPUTE_STUDIO_LERP )
			{
				ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f;
				ent->origin[1] += ( ent->curstate.origin[1] - ent->latched.prevorigin[1] ) * f;
				ent->origin[2] += ( ent->curstate.origin[2] - ent->latched.prevorigin[2] ) * f;

				for( i = 0; i < 3; i++ )
				{
					float	ang1, ang2;

					ang1 = ent->angles[i];
					ang2 = ent->latched.prevangles[i];
					d = ang1 - ang2;
					if( d > 180.0f ) d -= 360.0f;
					else if( d < -180.0f ) d += 360.0f;
					ent->angles[i] += d * f;
				}
			}
		}
	}
}
Ejemplo n.º 16
0
/*
=================
CL_PredictMovement

Sets cl.predicted_origin and cl.predicted_angles
=================
*/
void CL_PredictMovement()
{
	int	frame;
	int	ack, outgoing_command;
	int	current_command;
	int	current_command_mod;
	cl_entity_t	*player, *viewent;
	clientdata_t	*cd;

	if( cls.state != ca_active )
		return;

	if( cls.demoplayback && cl.refdef.cmd != NULL )
		VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles ); // restore viewangles from cmd.angles

	if(cl.refdef.paused /*|| cls.key_dest == key_menu*/)
		//return;

	player = CL_GetLocalPlayer ();
	viewent = CL_GetEntityByIndex( cl.refdef.viewentity );
	cd = &cl.frame.local.client;

	// unpredicted pure angled values converted into axis
	AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up );

	if( !CL_IsPredicted( ))
	{	
		// run commands even if client predicting is disabled - client expect it
		clgame.pmove->runfuncs = true;
		CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand );
		return;
	};

	ack = cls.netchan.incoming_acknowledged;
	outgoing_command = cls.netchan.outgoing_sequence;
	
	// if we are too far out of date, just freeze
	if(outgoing_command - ack >= CL_UPDATE_BACKUP)
	{
		//if(cl_showmiss->value)
			//Com_Printf ("exceeded CL_UPDATE_BACKUP\n");
		return;	
	};

	ASSERT( cl.refdef.cmd != NULL );

	// setup initial pmove state
	CL_SetupPMove( clgame.pmove, cd, &player->curstate, cl.refdef.cmd );
	clgame.pmove->runfuncs = false;
	
	frame = 0;

	while(++ack < outgoing_command)
	{
		// we've run too far forward
		//if( frame >= CL_UPDATE_BACKUP - 1 )
		//	break;
		
		frame = ack & (CL_UPDATE_BACKUP - 1);

		// Incoming_acknowledged is the last usercmd the server acknowledged having acted upon
		current_command = ack + frame;
		current_command_mod = current_command & CL_UPDATE_MASK;

		// we've caught up to the current command
		// this was the most up to date command
		if(current_command >= outgoing_command)
			break;

		clgame.pmove->cmd = cl.cmds[current_command_mod];

		// Call the client dll player movement function (and it will call the PM_Move())
		clgame.dllFuncs.pfnPlayerMove(clgame.pmove, false); // run frames
		clgame.pmove->runfuncs = ( current_command > outgoing_command - 1 ) ? true : false; // Prevent to play sounds/etc more that once
		
		frame++;
	};

	CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand );

	// copy results out for rendering
	VectorCopy( clgame.pmove->view_ofs, cl.predicted_viewofs );
	VectorCopy( clgame.pmove->origin, cl.predicted_origin );
	VectorCopy( clgame.pmove->velocity, cl.predicted_velocity );
};
Ejemplo n.º 17
0
// Shoots a decal onto the surface of the BSP.  position is the center of the decal in world coords
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, vec3_t saxis, float scale )
{
	decalinfo_t	decalInfo;
	hull_t		*hull;
	cl_entity_t	*ent = NULL;
	model_t		*model = NULL;
	int		width, height;

	if( textureIndex <= 0 || textureIndex >= MAX_TEXTURES )
	{
		MsgDev( D_ERROR, "Decal has invalid texture!\n" );
		return;
	}

	if( entityIndex > 0 )
	{
		ent = CL_GetEntityByIndex( entityIndex );

		if( modelIndex > 0 ) model = Mod_Handle( modelIndex );
		else if( ent != NULL ) model = Mod_Handle( ent->curstate.modelindex );
		else return;
	}
	else if( modelIndex > 0 )
		model = Mod_Handle( modelIndex );
	else model = cl.worldmodel;

	if( !model ) return;
	
	if( model->type != mod_brush )
	{
		MsgDev( D_ERROR, "Decals must hit mod_brush!\n" );
		return;
	}

	decalInfo.m_pModel = model;
	hull = &model->hulls[0];	// always use #0 hull

	if( ent && !( flags & FDECAL_LOCAL_SPACE ))
	{
		vec3_t	pos_l;

		// transform decal position in local bmodel space
		if( !VectorIsNull( ent->angles ))
		{
			matrix4x4	matrix;

			Matrix4x4_CreateFromEntity( matrix, ent->angles, ent->origin, 1.0f );
			Matrix4x4_VectorITransform( matrix, pos, pos_l );
		}
		else
		{
			VectorSubtract( pos, ent->origin, pos_l );
		}

		VectorCopy( pos_l, decalInfo.m_Position );
		flags |= FDECAL_LOCAL_SPACE; // decal position moved into local space
	}
	else
	{
		// pass position in global
		VectorCopy( pos, decalInfo.m_Position );
	}

	// deal with the s axis if one was passed in
	if( saxis )
	{
		flags |= FDECAL_USESAXIS;
		VectorCopy( saxis, decalInfo.m_SAxis );
	}

	// this decal must use landmark for correct transition
	if(!( model->flags & MODEL_HAS_ORIGIN ))
	{
		flags |= FDECAL_USE_LANDMARK;
	}

	// more state used by R_DecalNode()
	decalInfo.m_iTexture = textureIndex;
	decalInfo.m_Entity = entityIndex;
	decalInfo.m_Flags = flags;

	R_GetDecalDimensions( textureIndex, &width, &height );
	decalInfo.m_Size = width >> 1;
	if(( height >> 1 ) > decalInfo.m_Size )
		decalInfo.m_Size = height >> 1;

	decalInfo.m_scale = bound( MIN_DECAL_SCALE, scale, MAX_DECAL_SCALE );

	// compute the decal dimensions in world space
	decalInfo.m_decalWidth = width / decalInfo.m_scale;
	decalInfo.m_decalHeight = height / decalInfo.m_scale;

	R_DecalNode( model, &model->nodes[hull->firstclipnode], &decalInfo );
}
Ejemplo n.º 18
0
/*
=========================================================================

FRAME PARSING

=========================================================================
*/
void CL_UpdateEntityFields( cl_entity_t *ent )
{
	VectorCopy( ent->curstate.origin, ent->origin );
	VectorCopy( ent->curstate.angles, ent->angles );

	ent->model = Mod_Handle( ent->curstate.modelindex );
	ent->curstate.msg_time = cl.time;

	if( ent->player ) // stupid Half-Life bug
		ent->angles[PITCH] = -ent->angles[PITCH] / 3.0f;

	// make me lerp
	if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f )
	{
		float		d, f = 0.0f;
		int		i;

		// don't do it if the goalstarttime hasn't updated in a while.
		// NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
		// was increased to 1.0 s., which is 2x the max lag we are accounting for.
		if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime ))
			f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime );

		f = f - 1.0f;

		ent->origin[0] += ( ent->origin[0] - ent->latched.prevorigin[0] ) * f;
		ent->origin[1] += ( ent->origin[1] - ent->latched.prevorigin[1] ) * f;
		ent->origin[2] += ( ent->origin[2] - ent->latched.prevorigin[2] ) * f;

		for( i = 0; i < 3; i++ )
		{
			float	ang1, ang2;

			ang1 = ent->angles[i];
			ang2 = ent->latched.prevangles[i];
			d = ang1 - ang2;
			if( d > 180.0f ) d -= 360.0f;
			else if( d < -180.0f ) d += 360.0f;
			ent->angles[i] += d * f;
		}
	}
	else if( ent->curstate.eflags & EFLAG_SLERP )
	{
		float		d, f = 0.0f;
		cl_entity_t	*m_pGround = NULL;
		int		i;

		// don't do it if the goalstarttime hasn't updated in a while.
		// NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
		// was increased to 1.0 s., which is 2x the max lag we are accounting for.
		if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime ))
			f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime );

		f = f - 1.0f;

		if( ent->curstate.movetype == MOVETYPE_FLY )
		{
			ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f;
			ent->origin[1] += ( ent->curstate.origin[1] - ent->latched.prevorigin[1] ) * f;
			ent->origin[2] += ( ent->curstate.origin[2] - ent->latched.prevorigin[2] ) * f;

			for( i = 0; i < 3; i++ )
			{
				float	ang1, ang2;

				ang1 = ent->curstate.angles[i];
				ang2 = ent->latched.prevangles[i];
				d = ang1 - ang2;
				if( d > 180.0f ) d -= 360.0f;
				else if( d < -180.0f ) d += 360.0f;
				ent->angles[i] += d * f;
			}
		}
		else if( ent->curstate.movetype == MOVETYPE_STEP )
		{
			vec3_t	vecSrc, vecEnd;
			pmtrace_t	trace;

			if( ent->model )
			{
				CL_SetTraceHull( 0 ); // g-cont. player hull for better detect moving platforms
				VectorSet( vecSrc, ent->origin[0], ent->origin[1], ent->origin[2] + ent->model->maxs[2] );
				VectorSet( vecEnd, vecSrc[0], vecSrc[1], vecSrc[2] - ent->model->mins[2] - 8.0f );		
				CL_PlayerTraceExt( vecSrc, vecEnd, PM_STUDIO_IGNORE, CL_PushMoveFilter, &trace );
				m_pGround = CL_GetEntityByIndex( pfnIndexFromTrace( &trace ));
			}

			if( m_pGround && m_pGround->curstate.movetype == MOVETYPE_PUSH )
			{
				qboolean	applyVel, applyAvel;

				d = -1.0f;

				applyVel = !VectorCompare( m_pGround->curstate.origin, m_pGround->prevstate.origin );
				applyAvel = !VectorCompare( m_pGround->curstate.angles, m_pGround->prevstate.angles );

				if( applyVel || applyAvel )
				{
					ent->origin[0] += ( m_pGround->curstate.origin[0] - m_pGround->prevstate.origin[0] ) * d;
					ent->origin[1] += ( m_pGround->curstate.origin[1] - m_pGround->prevstate.origin[1] ) * d;
//					ent->origin[2] += ( m_pGround->curstate.origin[2] - m_pGround->prevstate.origin[2] ) * d;
					ent->latched.prevorigin[2] = ent->origin[2];
				}

				if( applyAvel )
				{
					for( i = 0; i < 3; i++ )
					{
						float	ang1, ang2;

						ang1 = m_pGround->curstate.angles[i];
						ang2 = m_pGround->prevstate.angles[i];
						f = ang1 - ang2;
						if( d > 180.0f ) f -= 360.0f;
						else if( d < -180.0f ) f += 360.0f;
						ent->angles[i] += d * f;
					}
				}
			}
		}
	}
}
Ejemplo n.º 19
0
/*
=============
CL_ParseEvent

=============
*/
void CL_ParseEvent( sizebuf_t *msg )
{
	int		event_index;
	int		i, num_events;
	int		packet_ent;
	event_args_t	nullargs, args;
	qboolean		has_update;
	entity_state_t	*state;
	cl_entity_t	*pEnt;
	float		delay;

	Q_memset( &nullargs, 0, sizeof( nullargs ));

	num_events = BF_ReadUBitLong( msg, 5 );

	// parse events queue
	for( i = 0 ; i < num_events; i++ )
	{
		event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS );
		Q_memset( &args, 0, sizeof( args ));
		has_update = false;

		if( BF_ReadOneBit( msg ))
		{
			packet_ent = BF_ReadUBitLong( msg, MAX_ENTITY_BITS );

			if( BF_ReadOneBit( msg ))
			{
				MSG_ReadDeltaEvent( msg, &nullargs, &args );
				has_update = true;
			}
		}
		else packet_ent = -1;

		if( packet_ent != -1 )
			state = &cls.packet_entities[(cl.frame.first_entity+packet_ent)%cls.num_client_entities];
		else state = NULL;

		// it's a client. Override some params
		if( args.entindex >= 1 && args.entindex <= cl.maxclients )
		{
			if(( args.entindex - 1 ) == cl.playernum )
			{
				if( state && !CL_IsPredicted( ))
				{
					// restore viewangles from angles
					args.angles[PITCH] = -state->angles[PITCH] * 3;
					args.angles[YAW] = state->angles[YAW];
					args.angles[ROLL] = 0; // no roll
				}
				else
				{
					// get the predicted angles
					VectorCopy( cl.refdef.cl_viewangles, args.angles );
				}

				VectorCopy( cl.frame.local.client.origin, args.origin );
				VectorCopy( cl.frame.local.client.velocity, args.velocity );
			}
			else if( state )
			{
				// restore viewangles from angles
				args.angles[PITCH] = -state->angles[PITCH] * 3;
				args.angles[YAW] = state->angles[YAW];
				args.angles[ROLL] = 0; // no roll

				// if we restore origin and velocity everytime, why don't do it here also?
				if( VectorIsNull( args.origin ))
					VectorCopy( state->origin, args.origin );
				if( VectorIsNull( args.velocity ))
					VectorCopy( state->velocity, args.velocity );
			}
		}
		else if( state )
		{
			if( VectorIsNull( args.origin ))
				VectorCopy( state->origin, args.origin );
			if( VectorIsNull( args.angles ))
				VectorCopy( state->angles, args.angles );
			if( VectorIsNull( args.velocity ))
				VectorCopy( state->velocity, args.velocity );
		}
		else if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL )
		{
			if( VectorIsNull( args.origin ))
				VectorCopy( pEnt->curstate.origin, args.origin );
			if( VectorIsNull( args.angles ))
				VectorCopy( pEnt->curstate.angles, args.angles );
			if( VectorIsNull( args.velocity ))
				VectorCopy( pEnt->curstate.velocity, args.velocity );
		}

		if( BF_ReadOneBit( msg ))
			delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f);
		else delay = 0.0f;

		// g-cont. should we need find the event with same index?
		CL_QueueEvent( 0, event_index, delay, &args );
	}
}
Ejemplo n.º 20
0
/*
=================
CL_PrepVideo

Call before entering a new level, or after changing dlls
=================
*/
void CL_PrepVideo( void )
{
	string	mdlname, mapname;
	int	i, mdlcount, step;
	int	map_checksum; // dummy

	if( !cl.model_precache[1][0] )
		return; // no map loaded

	Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar
	MsgDev( D_NOTE, "CL_PrepVideo: %s\n", clgame.mapname );

	// let the render dll load the map
	Q_strncpy( mapname, cl.model_precache[1], MAX_STRING ); 
	Mod_LoadWorld( mapname, (uint *)&map_checksum, false );
	cl.worldmodel = Mod_Handle( 1 ); // get world pointer
	Cvar_SetFloat( "scr_loading", 25.0f );

	SCR_UpdateScreen();

	// make sure what map is valid
	if( !cls.demoplayback && map_checksum != cl.checksum )
		Host_Error( "Local map version differs from server: %i != '%i'\n", map_checksum, cl.checksum );

	for( i = 0, mdlcount = 0; i < MAX_MODELS && cl.model_precache[i+1][0]; i++ )
		mdlcount++; // total num models
	step = mdlcount/10;

	for( i = 0; i < MAX_MODELS && cl.model_precache[i+1][0]; i++ )
	{
		Q_strncpy( mdlname, cl.model_precache[i+1], MAX_STRING );
		Mod_RegisterModel( mdlname, i+1 );
		Cvar_SetFloat( "scr_loading", scr_loading->value + 75.0f / mdlcount );
		if( step && !( i % step ) && ( cl_allow_levelshots->integer || cl.background ) )
			SCR_UpdateScreen();
	}

	// update right muzzleflash indexes
	CL_RegisterMuzzleFlashes ();

	// invalidate all decal indexes
	Q_memset( cl.decal_index, 0, sizeof( cl.decal_index ));

	CL_ClearWorld ();

	R_NewMap(); // tell the render about new map

	V_SetupOverviewState(); // set overview bounds

	// must be called after lightmap loading!
	clgame.dllFuncs.pfnVidInit();

	// release unused SpriteTextures
	for( i = 1; i < MAX_IMAGES; i++ )
	{
		if( !clgame.sprites[i].name[0] ) continue; // free slot
		if( clgame.sprites[i].needload != clgame.load_sequence )
			Mod_UnloadSpriteModel( &clgame.sprites[i] );
	}

	Mod_FreeUnused ();

	Q_memset( cl.playermodels, 0, sizeof( cl.playermodels ) );

	Cvar_SetFloat( "scr_loading", 100.0f );	// all done

	if( host.decalList )
	{
		// need to reapply all decals after restarting
		for( i = 0; i < host.numdecals; i++ )
		{
			decallist_t *entry = &host.decalList[i];
			cl_entity_t *pEdict = CL_GetEntityByIndex( entry->entityIndex );
			int decalIndex = CL_DecalIndex( CL_DecalIndexFromName( entry->name ));
			int modelIndex = 0;

			if( pEdict ) modelIndex = pEdict->curstate.modelindex;
			CL_DecalShoot( decalIndex, entry->entityIndex, modelIndex, entry->position, entry->flags );
		}
		Z_Free( host.decalList );
	}

	host.decalList = NULL; 
	host.numdecals = 0;

	if( host.soundList )
	{
		// need to reapply all ambient sounds after restarting
		for( i = 0; i < host.numsounds; i++ )
		{
			soundlist_t *entry = &host.soundList[i];
			if( entry->looping && entry->entnum != -1 )
			{
				MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name );
				S_AmbientSound( entry->origin, entry->entnum,
				S_RegisterSound( entry->name ), entry->volume, entry->attenuation,
				entry->pitch, 0 );
			}
		}
	}

	host.soundList = NULL; 
	host.numsounds = 0;
	
	if( host.developer <= 2 )
		Con_ClearNotify(); // clear any lines of console text

	SCR_UpdateScreen ();

	cl.video_prepped = true;
	cl.force_refdef = true;
}
Ejemplo n.º 21
0
/*
=================
CL_PredictMovement

Sets cl.predicted_origin and cl.predicted_angles
=================
*/
void CL_PredictMovement( void )
{
	int		frame = 1;
	int		ack, outgoing_command;
	int		current_command;
	int		current_command_mod;
	cl_entity_t	*player, *viewent;
	clientdata_t	*cd;

	if( cls.state != ca_active ) return;

	if( cls.demoplayback && cl.refdef.cmd != NULL )
	{
		// restore viewangles from cmd.angles
		VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles );
	}

	if( cl.refdef.paused || cls.key_dest == key_menu ) return;

	player = CL_GetLocalPlayer ();
	viewent = CL_GetEntityByIndex( cl.refdef.viewentity );
	cd = &cl.frame.local.client;

	// unpredicted pure angled values converted into axis
	AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up );

	if( !CL_IsPredicted( ))
	{	
		// run commands even if client predicting is disabled - client expected it
		clgame.pmove->runfuncs = true;
		CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand );
		return;
	}

	ack = cls.netchan.incoming_acknowledged;
	outgoing_command = cls.netchan.outgoing_sequence;

	ASSERT( cl.refdef.cmd != NULL );

	// setup initial pmove state
	CL_SetupPMove( clgame.pmove, cd, &player->curstate, cl.refdef.cmd );
	clgame.pmove->runfuncs = false;

	while( 1 )
	{
		// we've run too far forward
		if( frame >= CL_UPDATE_BACKUP - 1 )
			break;

		// Incoming_acknowledged is the last usercmd the server acknowledged having acted upon
		current_command = ack + frame;
		current_command_mod = current_command & CL_UPDATE_MASK;

		// we've caught up to the current command.
		if( current_command >= outgoing_command )
			break;

		clgame.pmove->cmd = cl.cmds[current_command_mod];

		// motor!
		clgame.dllFuncs.pfnPlayerMove( clgame.pmove, false ); // run frames
		clgame.pmove->runfuncs = ( current_command > outgoing_command - 1 ) ? true : false;

		frame++;
	}

	CL_PostRunCmd( cl.refdef.cmd, frame );
		
	// copy results out for rendering
	VectorCopy( clgame.pmove->view_ofs, cl.predicted_viewofs );
	VectorCopy( clgame.pmove->origin, cl.predicted_origin );
	VectorCopy( clgame.pmove->velocity, cl.predicted_velocity );
}