Beispiel #1
0
/*
================
R_PlaneForMirror

Get transformed mirrorplane and entity matrix
================
*/
void R_PlaneForMirror( msurface_t *surf, mplane_t *out, matrix4x4 m )
{
	cl_entity_t	*ent;

	ASSERT( out != NULL );

	ent = RI.currententity;

	// setup mirror plane
	*out = *surf->plane;

	if( surf->flags & SURF_PLANEBACK )
	{
		VectorNegate( out->normal, out->normal );
		out->dist = -out->dist;
	}

	if( !VectorIsNull( ent->origin ) || !VectorIsNull( ent->angles ))
	{
		mplane_t	tmp;

		if( !VectorIsNull( ent->angles )) Matrix4x4_CreateFromEntity( m, ent->angles, ent->origin, 1.0f );
		else Matrix4x4_CreateFromEntity( m, vec3_origin, ent->origin, 1.0f );

		tmp = *out;

		// transform mirror plane by entity matrix
		Matrix4x4_TransformPositivePlane( m, tmp.normal, tmp.dist, out->normal, &out->dist );
	}
	else Matrix4x4_LoadIdentity( m );
}
Beispiel #2
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 );
}
Beispiel #3
0
/*
===============
R_StaticEntity

Static entity is the brush which has no custom origin and not rotated
typically is a func_wall, func_breakable, func_ladder etc
===============
*/
static qboolean R_StaticEntity( cl_entity_t *ent )
{
	if( !gl_allow_static->integer )
		return false;

	if( ent->curstate.rendermode != kRenderNormal )
		return false;

	if( ent->model->type != mod_brush )
		return false;

	if( ent->curstate.effects & ( EF_NOREFLECT|EF_REFLECTONLY ))
		return false;

	if( ent->curstate.frame || ent->model->flags & MODEL_CONVEYOR )
		return false;

	if( ent->curstate.scale ) // waveheight specified
		return false;

	if( !VectorIsNull( ent->origin ) || !VectorIsNull( ent->angles ))
		return false;

	return true;
}
Beispiel #4
0
/*
================
SV_Physics_Pusher

================
*/
void SV_Physics_Pusher( edict_t *ent )
{
	float	oldtime, oldtime2;
	float	thinktime, movetime;
	edict_t	*pBlocker;

	pBlocker = NULL;
	oldtime = ent->v.ltime;
	thinktime = ent->v.nextthink;

	if( thinktime < oldtime + host.frametime )
	{
		movetime = thinktime - oldtime;
		if( movetime < 0.0f ) movetime = 0.0f;
	}
	else movetime = host.frametime;

	if( movetime )
	{
		if( !VectorIsNull( ent->v.avelocity ))
		{
			if( !VectorIsNull( ent->v.velocity ))
			{
				pBlocker = SV_PushRotate( ent, movetime );

				if( !pBlocker )
				{
					oldtime2 = ent->v.ltime;

					// reset the local time to what it was before we rotated
					ent->v.ltime = oldtime;
					pBlocker = SV_PushMove( ent, movetime );
					if( oldtime2 < ent->v.ltime )
						ent->v.ltime = oldtime2;
				}
			}
			else
			{
				pBlocker = SV_PushRotate( ent, movetime );
			}
		}
		else 
		{
			pBlocker = SV_PushMove( ent, movetime );
		}
	}

	// if the pusher has a "blocked" function, call it
	// otherwise, just stay in place until the obstacle is gone
	if( pBlocker ) svgame.dllFuncs.pfnBlocked( ent, pBlocker );

	if( thinktime > oldtime && (( ent->v.flags & FL_ALWAYSTHINK ) || thinktime <= ent->v.ltime ))
	{
		ent->v.nextthink = 0.0f;
		svgame.globals->time = sv.time;
		svgame.dllFuncs.pfnThink( ent );
		if( ent->free ) return;
	}
}
Beispiel #5
0
/*
=============
CL_PlaybackEvent

=============
*/
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
	float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
{
	event_args_t	args;
	int		invokerIndex = 0;

	// first check event for out of bounds
	if( eventindex < 1 || eventindex > MAX_EVENTS )
	{
		MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
		return;
	}


	if( flags & FEV_SERVER )
	{
		MsgDev( D_WARN, "CL_PlaybackEvent: event with FEV_SERVER flag!\n" );
		return;
	}

	// check event for precached
	if( !CL_EventIndex( cl.event_precache[eventindex] ))
	{
		MsgDev( D_ERROR, "CL_PlaybackEvent: event %i was not precached\n", eventindex );
		return;		
	}

	flags |= FEV_CLIENT; // it's a client event
	flags &= ~(FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL);

	if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
	invokerIndex = cl.playernum + 1; // only local client can issue client events

	args.flags = 0;
	args.entindex = invokerIndex;

	if( !angles || VectorIsNull( angles ))
		VectorCopy( cl.refdef.cl_viewangles, args.angles );
	else
		VectorCopy( angles, args.angles );

	if( !origin || VectorIsNull( origin ))
		VectorCopy( cl.frame.local.client.origin, args.origin );
	else
		VectorCopy( origin, args.origin );

	VectorCopy( cl.frame.local.client.velocity, args.velocity );
	args.ducking = cl.frame.local.playerstate.usehull == 1;

	args.fparam1 = fparam1;
	args.fparam2 = fparam2;
	args.iparam1 = iparam1;
	args.iparam2 = iparam2;
	args.bparam1 = bparam1;
	args.bparam2 = bparam2;

	CL_QueueEvent( flags, eventindex, delay, &args );
}
/*
====================
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++;
			}
		}
	}
}
Beispiel #7
0
/*
=============
SV_CheckMover

test thing (applies the friction to pushables while standing on moving platform)
=============
*/
qboolean SV_CheckMover( edict_t *ent )
{
	edict_t	*gnd = ent->v.groundentity;

	if( !SV_IsValidEdict( gnd ))
		return false;

	if( gnd->v.movetype != MOVETYPE_PUSH )
		return false;

	if( VectorIsNull( gnd->v.velocity ) && VectorIsNull( gnd->v.avelocity ))
		return false;

	return true;
}
Beispiel #8
0
/*
==================
PM_TraceTexture

find the face where the traceline hit
assume physentity is valid
==================
*/
msurface_t *PM_TraceSurface( physent_t *pe, vec3_t start, vec3_t end )
{
	matrix4x4		matrix;
	model_t		*bmodel;
	hull_t		*hull;
	vec3_t		start_l, end_l;
	vec3_t		offset;

	bmodel = pe->model;

	if( !bmodel || bmodel->type != mod_brush )
		return NULL;

	hull = &pe->model->hulls[0];
	VectorSubtract( hull->clip_mins, vec3_origin, offset );
	VectorAdd( offset, pe->origin, offset );

	VectorSubtract( start, offset, start_l );
	VectorSubtract( end, offset, end_l );

	// rotate start and end into the models frame of reference
	if( !VectorIsNull( pe->angles ))
	{
		Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
		Matrix4x4_VectorITransform( matrix, start, start_l );
		Matrix4x4_VectorITransform( matrix, end, end_l );
	}

	return PM_RecursiveSurfCheck( bmodel, &bmodel->nodes[hull->firstclipnode], start_l, end_l );
}
Beispiel #9
0
//============================================================================
static void SV_Physics_Entity( edict_t *ent )
{
	// user dll can override movement type (Xash3D extension)
	if( svgame.physFuncs.SV_PhysicsEntity && svgame.physFuncs.SV_PhysicsEntity( ent ))
		return; // overrided

	SV_UpdateBaseVelocity( ent );

	if(!( ent->v.flags & FL_BASEVELOCITY ) && !VectorIsNull( ent->v.basevelocity ))
	{
		// Apply momentum (add in half of the previous frame of velocity first)
		VectorMA( ent->v.velocity, 1.0f + (host.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
		VectorClear( ent->v.basevelocity );
	}
	ent->v.flags &= ~FL_BASEVELOCITY;

	if( svgame.globals->force_retouch != 0.0f )
	{
		// force retouch even for stationary
		SV_LinkEdict( ent, true );
	}

	switch( ent->v.movetype )
	{
	case MOVETYPE_NONE:
		SV_Physics_None( ent );
		break;
	case MOVETYPE_NOCLIP:
		SV_Physics_Noclip( ent );
		break;
	case MOVETYPE_FOLLOW:
		SV_Physics_Follow( ent );
		break;
	case MOVETYPE_COMPOUND:
		SV_Physics_Compound( ent );
		break;
	case MOVETYPE_STEP:
	case MOVETYPE_PUSHSTEP:
		SV_Physics_Step( ent );
		break;
	case MOVETYPE_FLY:
	case MOVETYPE_TOSS:
	case MOVETYPE_BOUNCE:
	case MOVETYPE_FLYMISSILE:
	case MOVETYPE_BOUNCEMISSILE:
		SV_Physics_Toss( ent );
		break;
	case MOVETYPE_PUSH:
		SV_Physics_Pusher( ent );
		break;
	case MOVETYPE_WALK:
		Host_Error( "SV_Physics: bad movetype %i\n", ent->v.movetype );
		break;
	}

	// g-cont. don't alow free entities during loading because
	// this produce a corrupted baselines
	if( sv.state == ss_active && ent->v.flags & FL_KILLME )
		SV_FreeEdict( ent );
}
/*
=============
CL_TruePointContents

=============
*/
int CL_TruePointContents( const vec3_t p )
{
	int	i, contents;
	int	oldhull;
	hull_t	*hull;
	vec3_t	test, offset;
	physent_t	*pe;

	// sanity check
	if( !p )
		return CONTENTS_NONE;

	oldhull = clgame.pmove->usehull;

	// get base contents from world
	contents = PM_HullPointContents( &cl.worldmodel->hulls[0], 0, p );

	for( i = 0; i < clgame.pmove->nummoveent; i++ )
	{
		pe = &clgame.pmove->moveents[i];

		if( pe->solid != SOLID_NOT ) // disabled ?
			continue;

		// only brushes can have special contents
		if( !pe->model || pe->model->type != mod_brush )
			continue;

		// check water brushes accuracy
		clgame.pmove->usehull = 2;
		hull = PM_HullForBsp( pe, clgame.pmove, offset );
		clgame.pmove->usehull = oldhull;

		// offset the test point appropriately for this hull.
		VectorSubtract( p, offset, test );

		if( (pe->model->flags & MODEL_HAS_ORIGIN) && !VectorIsNull( pe->angles ))
		{
			matrix4x4	matrix;
	
			Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
			Matrix4x4_VectorITransform( matrix, p, test );
		};

		// test hull for intersection with this model
		if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
			continue;

		// compare contents ranking
		if( RankForContents( pe->skin ) > RankForContents( contents ))
			contents = pe->skin; // new content has more priority
	};

	return contents;
}
/*
=============
CL_WaterEntity

=============
*/
int CL_WaterEntity( const float *rgflPos )
{
	physent_t		*pe;
	hull_t		*hull;
	vec3_t		test, offset;
	int		i, oldhull;

	if( !rgflPos )
		return -1;

	oldhull = clgame.pmove->usehull;

	for( i = 0; i < clgame.pmove->nummoveent; i++ )
	{
		pe = &clgame.pmove->moveents[i];

		if( pe->solid != SOLID_NOT ) // disabled ?
			continue;

		// only brushes can have special contents
		if( !pe->model || pe->model->type != mod_brush )
			continue;

		// check water brushes accuracy
		clgame.pmove->usehull = 2;
		hull = PM_HullForBsp( pe, clgame.pmove, offset );
		clgame.pmove->usehull = oldhull;

		// offset the test point appropriately for this hull.
		VectorSubtract( rgflPos, offset, test );

		if( (pe->model->flags & MODEL_HAS_ORIGIN) && !VectorIsNull( pe->angles ))
		{
			matrix4x4	matrix;
	
			Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
			Matrix4x4_VectorITransform( matrix, rgflPos, test );
		};

		// test hull for intersection with this model
		if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
			continue;

		// found water entity
		return pe->info;
	}
	return -1;
}
Beispiel #12
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;
}
Beispiel #13
0
static float pfnTraceModel( physent_t *pe, float *start, float *end, trace_t *trace )
{
	int	old_usehull;
	vec3_t	start_l, end_l;
	vec3_t	offset, temp;
	qboolean	rotated;
	matrix4x4	matrix;
	hull_t	*hull;

	old_usehull = clgame.pmove->usehull;
	clgame.pmove->usehull = 2;

	hull = PM_HullForBsp( pe, clgame.pmove, offset );

	clgame.pmove->usehull = old_usehull;

	if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles ))
		rotated = true;
	else rotated = false;

 	if( rotated )
 	{
 		Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
 		Matrix4x4_VectorITransform( matrix, start, start_l );
 		Matrix4x4_VectorITransform( matrix, end, end_l );
 	}
 	else
 	{
 		VectorSubtract( start, offset, start_l );
 		VectorSubtract( end, offset, end_l );
 	}

	SV_RecursiveHullCheck( hull, hull->firstclipnode, 0, 1, start_l, end_l, trace );
	trace->ent = NULL;

	if( rotated )
	{
		VectorCopy( trace->plane.normal, temp );
		Matrix4x4_TransformPositivePlane( matrix, temp, trace->plane.dist, trace->plane.normal, &trace->plane.dist );
	}

	VectorLerp( start, trace->fraction, end, trace->endpos );

	return trace->fraction;
}
Beispiel #14
0
/*
============
SV_FlyMove

The basic solid body movement clip that slides along multiple planes
*steptrace - if not NULL, the trace results of any vertical wall hit will be stored
Returns the clipflags if the velocity was modified (hit something solid)
1 = floor
2 = wall / step
4 = dead stop
============
*/
int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace )
{
	int	i, j, numplanes, bumpcount, blocked;
	vec3_t	dir, end, planes[MAX_CLIP_PLANES];
	vec3_t	primal_velocity, original_velocity, new_velocity;
	float	d, time_left, allFraction;
	trace_t	trace;

	blocked = 0;
	VectorCopy( ent->v.velocity, original_velocity );
	VectorCopy( ent->v.velocity, primal_velocity );
	numplanes = 0;

	allFraction = 0.0f;
	time_left = time;

	for( bumpcount = 0; bumpcount < MAX_CLIP_PLANES - 1; bumpcount++ )
	{
		if( VectorIsNull( ent->v.velocity ))
			break;

		VectorMA( ent->v.origin, time_left, ent->v.velocity, end );
		trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );

		allFraction += trace.fraction;

		if( trace.allsolid )
		{	
			// entity is trapped in another solid
			VectorClear( ent->v.velocity );
			return 4;
		}

		if( trace.fraction > 0.0f )
		{	
			// actually covered some distance
			VectorCopy( trace.endpos, ent->v.origin );
			VectorCopy( ent->v.velocity, original_velocity );
			numplanes = 0;
		}

		if( trace.fraction == 1.0f )
			 break; // moved the entire distance

		if( !trace.ent )
			MsgDev( D_ERROR, "SV_FlyMove: trace.ent == NULL\n" );

		if( trace.plane.normal[2] > 0.7f )
		{
			blocked |= 1; // floor

         			if( trace.ent->v.solid == SOLID_BSP || trace.ent->v.solid == SOLID_SLIDEBOX ||
			trace.ent->v.movetype == MOVETYPE_PUSHSTEP || (trace.ent->v.flags & FL_CLIENT))
			{
				ent->v.flags |= FL_ONGROUND;
				ent->v.groundentity = trace.ent;
			}
		}

		if( trace.plane.normal[2] == 0.0f )
		{
			blocked |= 2; // step
			if( steptrace ) *steptrace = trace; // save for player extrafriction
		}

		// run the impact function
		SV_Impact( ent, trace.ent, &trace );

		// break if removed by the impact function
		if( ent->free ) break;

		time_left -= time_left * trace.fraction;

		// clipped to another plane
		if( numplanes >= MAX_CLIP_PLANES )
		{
			// this shouldn't really happen
			VectorClear( ent->v.velocity );
			break;
		}

		VectorCopy( trace.plane.normal, planes[numplanes] );
		numplanes++;

		// modify original_velocity so it parallels all of the clip planes
		for( i = 0; i < numplanes; i++ )
		{
			SV_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0f );

			for( j = 0; j < numplanes; j++ )
			{
				if( j != i )
				{
					if( DotProduct( new_velocity, planes[j] ) < 0.0f )
						break; // not ok
				}
			}

			if( j == numplanes )
				break;
		}

		if( i != numplanes )
		{
			// go along this plane
			VectorCopy( new_velocity, ent->v.velocity );
		}
		else
		{
			// go along the crease
			if( numplanes != 2 )
			{
				VectorClear( ent->v.velocity );
				break;
			}

			CrossProduct( planes[0], planes[1], dir );
			d = DotProduct( dir, ent->v.velocity );
			VectorScale( dir, d, ent->v.velocity );
		}

		// if current velocity is against the original velocity,
		// stop dead to avoid tiny occilations in sloping corners
		if( DotProduct( ent->v.velocity, primal_velocity ) <= 0.0f )
		{
			VectorClear( ent->v.velocity );
			break;
		}
	}

	if( allFraction == 0.0f )
		VectorClear( ent->v.velocity );

	return blocked;
}
Beispiel #15
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 );
}
Beispiel #16
0
/*
====================
SV_AddLinksToPmove

collect solid entities
====================
*/
void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t pmove_maxs )
{
    link_t	*l, *next;
    edict_t	*check, *pl;
    vec3_t	mins, maxs;
    physent_t	*pe;

    pl = EDICT_NUM( svgame.pmove->player_index + 1 );
    //ASSERT( SV_IsValidEdict( pl ));
    if( !SV_IsValidEdict( pl ) )
    {
        MsgDev( D_ERROR, "SV_AddLinksToPmove: you have broken clients!\n");
        return;
    }

    // touch linked edicts
    for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next )
    {
        next = l->next;
        check = EDICT_FROM_AREA( l );

        if( check->v.groupinfo != 0 )
        {
            if(( !svs.groupop && (check->v.groupinfo & pl->v.groupinfo ) == 0) ||
                    ( svs.groupop == 1 && ( check->v.groupinfo & pl->v.groupinfo ) != 0 ))
                continue;
        }

        if( ( ( check->v.owner > 0) && check->v.owner == pl ) || check->v.solid == SOLID_TRIGGER )
            continue; // player or player's own missile

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

        if( check->v.solid == SOLID_NOT && ( check->v.skin == CONTENTS_NONE || check->v.modelindex == 0 ))
            continue;

        // ignore monsterclip brushes
        if(( check->v.flags & FL_MONSTERCLIP ) && check->v.solid == SOLID_BSP )
            continue;

        if( check == pl ) continue;	// himself

        if( !sv_corpse_solid->value )
        {
            if((( check->v.flags & FL_CLIENT ) && check->v.health <= 0 ) || check->v.deadflag == DEAD_DEAD )
                continue;	// dead body
        }

        if( VectorIsNull( check->v.size ))
            continue;

        VectorCopy( check->v.absmin, mins );
        VectorCopy( check->v.absmax, maxs );

        if( check->v.flags & FL_CLIENT )
        {
            // trying to get interpolated values
            if( svs.currentPlayer )
                SV_GetTrueMinMax( svs.currentPlayer, ( NUM_FOR_EDICT( check ) - 1), mins, maxs );
        }

        if( !BoundsIntersect( pmove_mins, pmove_maxs, mins, maxs ))
            continue;

        if( svgame.pmove->numphysent < MAX_PHYSENTS )
        {
            pe = &svgame.pmove->physents[svgame.pmove->numphysent];

            if( SV_CopyEdictToPhysEnt( pe, check ))
                svgame.pmove->numphysent++;
        }
    }

    // recurse down both sides
    if( node->axis == -1 ) return;

    if( pmove_maxs[node->axis] > node->dist )
        SV_AddLinksToPmove( node->children[0], pmove_mins, pmove_maxs );
    if( pmove_mins[node->axis] < node->dist )
        SV_AddLinksToPmove( node->children[1], pmove_mins, pmove_maxs );
}
Beispiel #17
0
/*
=================
R_FindBmodelMirrors

Check all bmodel surfaces and make personal mirror chain
=================
*/
void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
{
	mextrasurf_t	*extrasurf;
	vec3_t		mins, maxs;
	msurface_t	*psurf;
	model_t		*clmodel;
	qboolean		rotated;
	int		i, clipFlags;

	clmodel = e->model;

	if( static_entity )
	{
		Matrix4x4_LoadIdentity( RI.objectMatrix );

		if( R_CullBox( clmodel->mins, clmodel->maxs, RI.clipFlags ))
			return;

		VectorCopy( RI.cullorigin, tr.modelorg );
		clipFlags = RI.clipFlags;
	}
	else
	{
		if( !VectorIsNull( e->angles ))
		{
			for( i = 0; i < 3; i++ )
			{
				mins[i] = e->origin[i] - clmodel->radius;
				maxs[i] = e->origin[i] + clmodel->radius;
			}
			rotated = true;
		}
		else
		{
			VectorAdd( e->origin, clmodel->mins, mins );
			VectorAdd( e->origin, clmodel->maxs, maxs );
			rotated = false;
		}

		if( R_CullBox( mins, maxs, RI.clipFlags ))
			return;

		if( !VectorIsNull( e->origin ) || !VectorIsNull( e->angles ))
		{
			if( rotated ) Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, 1.0f );
			else Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, 1.0f );
		}
		else Matrix4x4_LoadIdentity( RI.objectMatrix );

		e->visframe = tr.framecount; // visible

		if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg );
		else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg );

		clipFlags = 0;
	}

	psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
	for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
	{
		if(!( psurf->flags & SURF_REFLECT ))
			continue;

		if( R_CullSurface( psurf, clipFlags ))
			continue;

		extrasurf = SURF_INFO( psurf, RI.currentmodel );
		extrasurf->mirrorchain = tr.mirror_entities[tr.num_mirror_entities].chain;
		tr.mirror_entities[tr.num_mirror_entities].chain = extrasurf;
	}

	// store new mirror entity
	if( !static_entity && tr.mirror_entities[tr.num_mirror_entities].chain != NULL )
	{
		tr.mirror_entities[tr.num_mirror_entities].ent = RI.currententity;
		tr.num_mirror_entities++;
	}
}
Beispiel #18
0
/*
================
R_DrawMirrors

Draw all viewpasess from mirror position
Mirror textures will be drawn in normal pass
================
*/
void R_DrawMirrors( void )
{
	ref_instance_t	oldRI;
	mplane_t		plane;
	msurface_t	*surf, *surf2;
	int		i, oldframecount;
	mextrasurf_t	*es, *tmp, *mirrorchain;
	vec3_t		forward, right, up;
	vec3_t		origin, angles;
	matrix4x4		mirrormatrix;
	cl_entity_t	*e;
	model_t		*m;
	float		d;

	if( !tr.num_mirror_entities ) return; // mo mirrors for this frame

	oldRI = RI; // make refinst backup
	oldframecount = tr.framecount;

	for( i = 0; i < tr.num_mirror_entities; i++ )
	{
		mirrorchain = tr.mirror_entities[i].chain;

		for( es = mirrorchain; es != NULL; es = es->mirrorchain )
		{
			RI.currententity = e = tr.mirror_entities[i].ent;
			RI.currentmodel = m = RI.currententity->model;

			surf = INFO_SURF( es, m );

			ASSERT( RI.currententity != NULL );
			ASSERT( RI.currentmodel != NULL );

			// NOTE: copy mirrortexture and mirrormatrix from another surfaces
			// from this entity\world that has same planes and reduce number of viewpasses

			// make sure what we have one pass at least
			if( es != mirrorchain )
			{
				for( tmp = mirrorchain; tmp != es; tmp = tmp->mirrorchain )
				{
					surf2 = INFO_SURF( tmp, m );

					if( !tmp->mirrortexturenum )
						continue;	// not filled?

					if( surf->plane->dist != surf2->plane->dist )
						continue;

					if( !VectorCompare( surf->plane->normal, surf2->plane->normal ))
						continue;

					// found surface with same plane!
					break;
				}

				if( tmp != es && tmp && tmp->mirrortexturenum )
				{
					// just copy reflection texture from surface with same plane
					Matrix4x4_Copy( es->mirrormatrix, tmp->mirrormatrix );
					es->mirrortexturenum = tmp->mirrortexturenum;
					continue;	// pass skiped
				}
			} 

			R_PlaneForMirror( surf, &plane, mirrormatrix );

			d = -2.0f * ( DotProduct( RI.vieworg, plane.normal ) - plane.dist );
			VectorMA( RI.vieworg, d, plane.normal, origin );

			d = -2.0f * DotProduct( RI.vforward, plane.normal );
			VectorMA( RI.vforward, d, plane.normal, forward );
			VectorNormalize( forward );

			d = -2.0f * DotProduct( RI.vright, plane.normal );
			VectorMA( RI.vright, d, plane.normal, right );
			VectorNormalize( right );

			d = -2.0f * DotProduct( RI.vup, plane.normal );
			VectorMA( RI.vup, d, plane.normal, up );
			VectorNormalize( up );

			VectorsAngles( forward, right, up, angles );
			angles[ROLL] = -angles[ROLL];

			RI.params = RP_MIRRORVIEW|RP_CLIPPLANE|RP_OLDVIEWLEAF;

			RI.clipPlane = plane;
			RI.clipFlags |= ( 1<<5 );

			RI.frustum[5] = plane;
			RI.frustum[5].signbits = SignbitsForPlane( RI.frustum[5].normal );
			RI.frustum[5].type = PLANE_NONAXIAL;

			RI.refdef.viewangles[0] = anglemod( angles[0] );
			RI.refdef.viewangles[1] = anglemod( angles[1] );
			RI.refdef.viewangles[2] = anglemod( angles[2] );
			VectorCopy( origin, RI.refdef.vieworg );
			VectorCopy( origin, RI.cullorigin );

			// put pvsorigin before the mirror plane to avoid get full visibility on world mirrors
			if( RI.currententity == clgame.entities )
			{
				VectorMA( es->origin, 1.0f, plane.normal, origin );
			}
			else
			{
				Matrix4x4_VectorTransform( mirrormatrix, es->origin, origin );
				VectorMA( origin, 1.0f, plane.normal, origin );
			}

			VectorCopy( origin, RI.pvsorigin );

			// combine two leafs from client and mirror views
			r_viewleaf = Mod_PointInLeaf( oldRI.pvsorigin, cl.worldmodel->nodes );
			r_viewleaf2 = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );

			if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
			{
				// allow screen size
				RI.viewport[2] = bound( 96, RI.viewport[2], 1024 );
				RI.viewport[3] = bound( 72, RI.viewport[3], 768 );
			}
			else
			{
				RI.viewport[2] = NearestPOW( RI.viewport[2], true );
				RI.viewport[3] = NearestPOW( RI.viewport[3], true );
				RI.viewport[2] = bound( 128, RI.viewport[2], 1024 );
				RI.viewport[3] = bound( 64, RI.viewport[3], 512 );
			}

			tr.framecount++;
			R_RenderScene( &RI.refdef );
			r_stats.c_mirror_passes++;

			es->mirrortexturenum = R_AllocateMirrorTexture();

			// create personal projection matrix for mirror
			if( VectorIsNull( e->origin ) && VectorIsNull( e->angles ))
			{
				Matrix4x4_Copy( es->mirrormatrix, RI.worldviewProjectionMatrix );
			}
			else
			{
				Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, mirrormatrix );
				Matrix4x4_Concat( es->mirrormatrix, RI.projectionMatrix, RI.modelviewMatrix );
			}			

			RI = oldRI; // restore ref instance
		}

		// clear chain for this entity
		for( es = mirrorchain; es != NULL; )
		{
			tmp = es->mirrorchain;
			es->mirrorchain = NULL;
			es = tmp;
		}

		tr.mirror_entities[i].chain = NULL; // done
		tr.mirror_entities[i].ent = NULL;
	}

	r_oldviewleaf = r_viewleaf = NULL;	// force markleafs next frame
	tr.framecount = oldframecount;	// restore real framecount
	tr.num_mirror_entities = 0;
	tr.num_mirrors_used = 0;
}
Beispiel #19
0
/*
=============
SV_Physics_Toss

Toss, bounce, and fly movement.  When onground, do nothing.
=============
*/
void SV_Physics_Toss( edict_t *ent )
{
	trace_t	trace;
	vec3_t	move;
	float	backoff;
	edict_t	*ground;

	SV_CheckWater( ent );

	// regular thinking
	if( !SV_RunThink( ent )) return;

	ground = ent->v.groundentity;

	if( ent->v.velocity[2] > 0.0f || !SV_IsValidEdict( ground ) || ground->v.flags & (FL_MONSTER|FL_CLIENT) || svgame.globals->changelevel )
	{
		ent->v.flags &= ~FL_ONGROUND;
	}

	// if on ground and not moving, return.
	if( ent->v.flags & FL_ONGROUND && VectorIsNull( ent->v.velocity ))
	{
		VectorClear( ent->v.avelocity );

		if( VectorIsNull( ent->v.basevelocity ))
			return;	// at rest
	}

	SV_CheckVelocity( ent );

	// add gravity
	switch( ent->v.movetype )
	{
	case MOVETYPE_FLY:
	case MOVETYPE_FLYMISSILE:
	case MOVETYPE_BOUNCEMISSILE:
		break;
	default:
		SV_AddGravity( ent );
		break;
	}

	// move angles (with friction)
	switch( ent->v.movetype )
	{
	case MOVETYPE_TOSS:
	case MOVETYPE_BOUNCE:
		SV_AngularMove( ent, host.frametime, ent->v.friction );
		break;         
	default:
		SV_AngularMove( ent, host.frametime, 0.0f );
		break;
	}

	// move origin
	// Base velocity is not properly accounted for since this entity will move again
	// after the bounce without taking it into account
	VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );

	SV_CheckVelocity( ent );
	VectorScale( ent->v.velocity, host.frametime, move );

	VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );

	trace = SV_PushEntity( ent, move, vec3_origin, NULL );
	if( ent->free ) return;

	SV_CheckVelocity( ent );

	if( trace.allsolid )
	{
		// entity is trapped in another solid
		VectorClear( ent->v.avelocity );
		VectorClear( ent->v.velocity );
		return;
	}

	if( trace.fraction == 1.0f )
	{
		SV_CheckWaterTransition( ent );
		return;
	}

	if( ent->v.movetype == MOVETYPE_BOUNCE )
		backoff = 2.0f - ent->v.friction;
	else if( ent->v.movetype == MOVETYPE_BOUNCEMISSILE )
		backoff = 2.0f;
	else backoff = 1.0f;

	SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff );

	// stop if on ground
	if( trace.plane.normal[2] > 0.7f )
	{		
		float	vel;

		VectorAdd( ent->v.velocity, ent->v.basevelocity, move );
		vel = DotProduct( move, move );

		if( ent->v.velocity[2] < sv_gravity->value * host.frametime )
		{
			// we're rolling on the ground, add static friction.
			ent->v.groundentity = trace.ent;
			ent->v.flags |= FL_ONGROUND;
			ent->v.velocity[2] = 0.0f;
		}

		if( vel < 900.0f || ( ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE ))
		{
			ent->v.flags |= FL_ONGROUND;
			ent->v.groundentity = trace.ent;
			VectorClear( ent->v.avelocity );
			VectorClear( ent->v.velocity );
		}
		else
		{
			VectorScale( ent->v.velocity, (1.0f - trace.fraction) * host.frametime * 0.9f, move );
			VectorMA( move, (1.0f - trace.fraction) * host.frametime * 0.9f, ent->v.basevelocity, move );
			trace = SV_PushEntity( ent, move, vec3_origin, NULL );
			if( ent->free ) return;
		}
	}
	
	// check for in water
	SV_CheckWaterTransition( ent );
}
Beispiel #20
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 );
	}
}
Beispiel #21
0
/*
=============
SV_Physics_Step

Monsters freefall when they don't have a ground entity, otherwise
all movement is done with discrete steps.

This is also used for objects that have become still on the ground, but
will fall if the floor is pulled out from under them.
=============
*/
void SV_Physics_Step( edict_t *ent )
{
	qboolean	inwater;
	qboolean	wasonground;
	qboolean	wasonmover;
	vec3_t	mins, maxs;
	vec3_t	point;
	trace_t	trace;
	int	x, y;

	SV_WaterMove( ent );
	SV_CheckVelocity( ent );

	wasonground = (ent->v.flags & FL_ONGROUND);
	wasonmover = SV_CheckMover( ent );
	inwater = SV_CheckWater( ent );

	if( ent->v.flags & FL_FLOAT && ent->v.waterlevel > 0 )
	{
		float buoyancy = SV_Submerged( ent ) * ent->v.skin * host.frametime;

		SV_AddGravity( ent );
		ent->v.velocity[2] += buoyancy;
	}

	if( !wasonground && !( ent->v.flags & FL_FLY ) && (!( ent->v.flags & FL_SWIM ) || ent->v.waterlevel <= 0 ))
	{
		if( !inwater )
			SV_AddGravity( ent );
	}

	if( !VectorIsNull( ent->v.velocity ) || !VectorIsNull( ent->v.basevelocity ))
	{
		ent->v.flags &= ~FL_ONGROUND;

		if(( wasonground || wasonmover ) && ( ent->v.health > 0 || SV_CheckBottom( ent, MOVE_NORMAL )))
		{
			float	*vel = ent->v.velocity;
			float	control, speed, newspeed;
			float	friction;

			speed = sqrt(( vel[0] * vel[0] ) + ( vel[1] * vel[1] ));	// DotProduct2D

			if( speed )
			{
				friction = sv_friction->value * ent->v.friction;	// factor
				ent->v.friction = 1.0f; // g-cont. ???
				if( wasonmover ) friction *= 0.5f; // add a little friction

				control = (speed < sv_stopspeed->value) ? sv_stopspeed->value : speed;
				newspeed = speed - (host.frametime * control * friction);
				if( newspeed < 0 ) newspeed = 0;
				newspeed /= speed;

				vel[0] = vel[0] * newspeed;
				vel[1] = vel[1] * newspeed;
			}
		}

		VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
		SV_CheckVelocity( ent );

		SV_FlyMove( ent, host.frametime, NULL );
		if( ent->free ) return;

		SV_CheckVelocity( ent );
		VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );

		SV_CheckVelocity( ent );

		VectorAdd( ent->v.origin, ent->v.mins, mins );
		VectorAdd( ent->v.origin, ent->v.maxs, maxs );

		point[2] = mins[2] - 1.0f;

		for( x = 0; x <= 1; x++ )
		{
			if( ent->v.flags & FL_ONGROUND )
				break;

			for( y = 0; y <= 1; y++ )
			{
				point[0] = x ? maxs[0] : mins[0];
				point[1] = y ? maxs[1] : mins[1];

				trace = SV_Move( point, vec3_origin, vec3_origin, point, MOVE_NORMAL, ent );

				if( trace.startsolid )
				{
					ent->v.flags |= FL_ONGROUND;
					ent->v.groundentity = trace.ent;
					ent->v.friction = 1.0f;
					break;
				}
			}
		}

		SV_LinkEdict( ent, true );
	}
	else
	{
		if( svgame.globals->force_retouch != 0 )
		{
			trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent );

			// hentacle impact code
			if(( trace.fraction < 1.0f || trace.startsolid ) && SV_IsValidEdict( trace.ent ))
			{
				SV_Impact( ent, trace.ent, &trace );
				if( ent->free ) return;
			}
		}
	}

	if( !SV_RunThink( ent )) return;
	SV_CheckWaterTransition( ent );

}
Beispiel #22
0
/*
===========
SV_RunCmd
===========
*/
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
{
    usercmd_t lastcmd;
    edict_t	*clent, *touch;
    double	frametime;
    int	i, oldmsec;
    pmtrace_t	*pmtrace;
    trace_t	trace;
    vec3_t	oldvel;

    clent = cl->edict;

    if( cl->next_movetime > host.realtime )
    {
        cl->last_movetime += ( ucmd->msec * 0.001f );
        return;
    }

    cl->next_movetime = 0.0;

    // chop up very long commands
    if( ucmd->msec > 50 )
    {
        lastcmd = *ucmd;
        oldmsec = ucmd->msec;
        lastcmd.msec = oldmsec / 2;

        SV_RunCmd( cl, &lastcmd, random_seed );

        lastcmd.msec = oldmsec / 2 + (oldmsec & 1);	// give them back thier msec.
        lastcmd.impulse = 0;
        SV_RunCmd( cl, &lastcmd, random_seed );
        return;
    }

    if( !cl->fakeclient )
    {
        SV_SetupMoveInterpolant( cl );
    }

    lastcmd = *ucmd;
    svgame.dllFuncs.pfnCmdStart( cl->edict, ucmd, random_seed );

    frametime = ucmd->msec * 0.001;
    cl->timebase += frametime;
    cl->last_movetime += frametime;

    PM_CheckMovingGround( clent, frametime );

    VectorCopy( clent->v.v_angle, svgame.pmove->oldangles ); // save oldangles
    if( !clent->v.fixangle ) VectorCopy( ucmd->viewangles, clent->v.v_angle );

    VectorClear( clent->v.clbasevelocity );

    // copy player buttons
    clent->v.button = ucmd->buttons;
    if( ucmd->impulse ) clent->v.impulse = ucmd->impulse;

    if( ucmd->impulse == 204 )
    {
        // force client.dll update
        SV_RefreshUserinfo();
    }

    svgame.globals->time = cl->timebase;
    svgame.dllFuncs.pfnPlayerPreThink( clent );
    SV_PlayerRunThink( clent, frametime, cl->timebase );

    // If conveyor, or think, set basevelocity, then send to client asap too.
    if( !VectorIsNull( clent->v.basevelocity ))
        VectorCopy( clent->v.basevelocity, clent->v.clbasevelocity );

    // setup playermove state
    SV_SetupPMove( svgame.pmove, cl, ucmd, cl->physinfo );

    // motor!
    svgame.dllFuncs.pfnPM_Move( svgame.pmove, true );

    // copy results back to client
    SV_FinishPMove( svgame.pmove, cl );

    // link into place and touch triggers
    SV_LinkEdict( clent, true );
    VectorCopy( clent->v.velocity, oldvel ); // save velocity

    // touch other objects
    for( i = 0; i < svgame.pmove->numtouch; i++ )
    {
        // never touch the objects when "playersonly" is active
        if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY ))
            break;

        pmtrace = &svgame.pmove->touchindex[i];
        touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info );
        if( touch == clent ) continue;

        VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
        SV_ConvertPMTrace( &trace, pmtrace, touch );
        SV_Impact( touch, clent, &trace );
    }

    // restore velocity
    VectorCopy( oldvel, clent->v.velocity );

    svgame.pmove->numtouch = 0;
    svgame.globals->time = cl->timebase;
    svgame.globals->frametime = frametime;

    // run post-think
    svgame.dllFuncs.pfnPlayerPostThink( clent );
    svgame.dllFuncs.pfnCmdEnd( clent );

    if( !cl->fakeclient )
    {
        SV_RestoreMoveInterpolant( cl );
    }
}
Beispiel #23
0
int CL_InterpolateModel( cl_entity_t *e )
{
	position_history_t	*ph0, *ph1;
	vec3_t		origin, angles, delta;
	float		t, t1, t2, frac;
	int		i;

	VectorCopy( e->curstate.origin, e->origin );
	VectorCopy( e->curstate.angles, e->angles );

	if( e->model == NULL )
		return 1;

	t = cl.time - cl_interp->value;

	if( !CL_FindInterpolationUpdates( e, t, &ph0, &ph1, NULL ))
		return 0;

	if( ph0 == NULL || ph1 == NULL )
		return 0;

	t1 = ph0->animtime;
	t2 = ph1->animtime;

	if( t - t2 < 0.0f )
		return 0;

	if( t2 == 0.0f || VectorIsNull( ph1->origin ) && !VectorIsNull( ph0->origin ))
	{
		VectorCopy( ph0->origin, e->origin );
		VectorCopy( ph0->angles, e->angles );
		return 0;
	}

	if( t2 == t1 )
	{
		VectorCopy( ph0->origin, e->origin );
		VectorCopy( ph0->angles, e->angles );
		return 1;
	}

	VectorSubtract( ph0->origin, ph1->origin, delta );
	frac = (t - t2) / (t1 - t2);

	if( frac < 0.0f )
		return 0;

	if( frac > 1.0f )
		frac = 1.0f;

	VectorMA( ph1->origin, frac, delta, origin );

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

		ang1 = ph0->angles[i];
		ang2 = ph1->angles[i];
		d = ang1 - ang2;

		if( d > 180.0f ) d -= 360.0f;
		else if( d < -180.0f ) d += 360.0f;

		angles[i] = ang2 + d * frac;
	}

	VectorCopy( origin, e->origin );
	VectorCopy( angles, e->angles );

	return 1;
}
Beispiel #24
0
/*
=================
FinishBrush

produces a final brush based on the buildBrush->sides array
and links it to the current entity
=================
*/
brush_t *FinishBrush( void )
{
	brush_t		*b;
	
	// create windings for sides and bounds for brush
	if( !CreateBrushWindings( buildBrush ))
		return NULL;

	// origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
	// after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush
	if( buildBrush->compileFlags & C_ORIGIN )
	{
		char	string[32];
		vec3_t	size, movedir, origin;

		if( numEntities == 1 )
		{
			Msg( "Entity %i, Brush %i: origin brushes not allowed in world\n", mapEnt->mapEntityNum, entitySourceBrushes );
			return NULL;
		}
		
		// calcualte movedir (Xash 0.4 style)
		VectorAverage( buildBrush->mins, buildBrush->maxs, origin );
		VectorSubtract( buildBrush->maxs, buildBrush->mins, size );

		if( size[2] > size[0] && size[2] > size[1] )
            		VectorSet( movedir, 0.0f, 1.0f, 0.0f );	// x-rotate
		else if( size[1] > size[2] && size[1] > size[0] )
            		VectorSet( movedir, 1.0f, 0.0f, 0.0f );	// y-rotate
		else if( size[0] > size[2] && size[0] > size[1] )
			VectorSet( movedir, 0.0f, 0.0f, 1.0f );	// z-rotate
		else VectorClear( movedir ); // custom movedir

#if 0
		if( !VectorIsNull( movedir ))
		{
			com.snprintf( string, sizeof( string ), "%i %i %i", (int)movedir[0], (int)movedir[1], (int)movedir[2] );
			SetKeyValue( &entities[numEntities - 1], "movedir", string );
		}
#endif
		if(!VectorIsNull( origin ))
		{
			com.snprintf( string, sizeof( string ), "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2] );
			SetKeyValue( &entities[numEntities - 1], "origin", string );
			VectorCopy( origin, entities[numEntities - 1].origin );
                    }

		// don't keep this brush
		return NULL;
	}
	
	// determine if the brush is an area portal
	if( buildBrush->compileFlags & C_AREAPORTAL )
	{
		if( numEntities != 1 )
		{
			Msg( "Entity %i, Brush %i: areaportals only allowed in world\n", mapEnt->mapEntityNum, entitySourceBrushes );
			return NULL;
		}
	}
	
	AddBrushBevels();
	
	b = CopyBrush( buildBrush );
	
	b->entityNum = mapEnt->mapEntityNum;
	b->brushNum = entitySourceBrushes;
	
	b->original = b;
	
	// link opaque brushes to head of list, translucent brushes to end
	if( b->opaque || mapEnt->lastBrush == NULL )
	{
		b->next = mapEnt->brushes;
		mapEnt->brushes = b;
		if( mapEnt->lastBrush == NULL )
			mapEnt->lastBrush = b;
	}
	else
	{
		b->next = NULL;
		mapEnt->lastBrush->next = b;
		mapEnt->lastBrush = b;
	}
	
	// link colorMod volume brushes to the entity directly
	if( b->contentShader != NULL && b->contentShader->colorMod != NULL && b->contentShader->colorMod->type == CM_VOLUME )
	{
		b->nextColorModBrush = mapEnt->colorModBrushes;
		mapEnt->colorModBrushes = b;
	}
	return b;
}
Beispiel #25
0
/*
	PM_GroundMove

	Player is on ground, with no upwards velocity
*/
void
PM_GroundMove (void)
{
	vec3_t      start, dest;
	trace_t   trace;
	vec3_t      original, originalvel, down, up, downvel;
	float       downdist, updist;

	pmove.velocity[2] = 0;
	if (VectorIsNull(pmove.velocity))
		return;

	// first try just moving to the destination 
	dest[0] = pmove.origin[0] + pmove.velocity[0] * frametime;
	dest[1] = pmove.origin[1] + pmove.velocity[1] * frametime;
	dest[2] = pmove.origin[2];

	// first try moving directly to the next spot
	VectorCopy (dest, start);
	trace = PM_PlayerMove (pmove.origin, dest);
	if (trace.fraction == 1) {
		VectorCopy (trace.endpos, pmove.origin);
		return;
	}
	// try sliding forward both on ground and up 16 pixels
	// take the move that goes farthest
	VectorCopy (pmove.origin, original);
	VectorCopy (pmove.velocity, originalvel);

	// slide move
	PM_FlyMove ();

	VectorCopy (pmove.origin, down);
	VectorCopy (pmove.velocity, downvel);

	VectorCopy (original, pmove.origin);
	VectorCopy (originalvel, pmove.velocity);

// move up a stair height
	VectorCopy (pmove.origin, dest);
	dest[2] += STEPSIZE;
	trace = PM_PlayerMove (pmove.origin, dest);
	if (!trace.startsolid && !trace.allsolid) {
		VectorCopy (trace.endpos, pmove.origin);
	}
// slide move
	PM_FlyMove ();

// press down the stepheight
	VectorCopy (pmove.origin, dest);
	dest[2] -= STEPSIZE;
	trace = PM_PlayerMove (pmove.origin, dest);
	if (trace.plane.normal[2] < 0.7)
		goto usedown;
	if (!trace.startsolid && !trace.allsolid) {
		VectorCopy (trace.endpos, pmove.origin);
	}
	VectorCopy (pmove.origin, up);

	// decide which one went farther
	downdist = (down[0] - original[0]) * (down[0] - original[0])
		+ (down[1] - original[1]) * (down[1] - original[1]);
	updist = (up[0] - original[0]) * (up[0] - original[0])
		+ (up[1] - original[1]) * (up[1] - original[1]);

	if (downdist > updist) {
	  usedown:
		VectorCopy (down, pmove.origin);
		VectorCopy (downvel, pmove.velocity);
	} else								// copy z value from slide move
		pmove.velocity[2] = downvel[2];

// if at a dead stop, retry the move with nudges to get around lips

}
Beispiel #26
0
/*
============
SV_PushMove

============
*/
static edict_t *SV_PushMove( edict_t *pusher, float movetime )
{
	int		i, e, block;
	int		num_moved, oldsolid;
	vec3_t		mins, maxs, lmove;
	sv_pushed_t	*p, *pushed_p;
	edict_t		*check;	

	if( svgame.globals->changelevel || VectorIsNull( pusher->v.velocity ))
	{
		pusher->v.ltime += movetime;
		return NULL;
	}

	for( i = 0; i < 3; i++ )
	{
		lmove[i] = pusher->v.velocity[i] * movetime;
		mins[i] = pusher->v.absmin[i] + lmove[i];
		maxs[i] = pusher->v.absmax[i] + lmove[i];
	}

	pushed_p = svgame.pushed;

	// save the pusher's original position
	pushed_p->ent = pusher;
	VectorCopy( pusher->v.origin, pushed_p->origin );
	VectorCopy( pusher->v.angles, pushed_p->angles );
	pushed_p++;
	
	// move the pusher to it's final position
	SV_LinearMove( pusher, movetime, 0.0f );
	SV_LinkEdict( pusher, false );
	pusher->v.ltime += movetime;
	oldsolid = pusher->v.solid;

	// non-solid pushers can't push anything
	if( pusher->v.solid == SOLID_NOT )
		return NULL;

	// see if any solid entities are inside the final position
	num_moved = 0;

	for( e = 1; e < svgame.numEntities; e++ )
	{
		check = EDICT_NUM( e );
		if( !SV_IsValidEdict( check )) continue;

		// filter movetypes to collide with
		if( !SV_CanPushed( check ))
			continue;

		pusher->v.solid = SOLID_NOT;
		block = SV_TestEntityPosition( check, pusher );
		pusher->v.solid = oldsolid;
		if( block ) continue;

		// if the entity is standing on the pusher, it will definately be moved
		if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
		{
			if( check->v.absmin[0] >= maxs[0]
			 || check->v.absmin[1] >= maxs[1]
			 || check->v.absmin[2] >= maxs[2]
			 || check->v.absmax[0] <= mins[0]
			 || check->v.absmax[1] <= mins[1]
			 || check->v.absmax[2] <= mins[2] )
				continue;

			// see if the ent's bbox is inside the pusher's final position
			if( !SV_TestEntityPosition( check, NULL ))
				continue;
		}

		// remove the onground flag for non-players
		if( check->v.movetype != MOVETYPE_WALK )
			check->v.flags &= ~FL_ONGROUND;

		// save original position of contacted entity
		pushed_p->ent = check;
		VectorCopy( check->v.origin, pushed_p->origin );
		VectorCopy( check->v.angles, pushed_p->angles );
		pushed_p++;

		// try moving the contacted entity 
		pusher->v.solid = SOLID_NOT;
		SV_PushEntity( check, lmove, vec3_origin, &block );
		pusher->v.solid = oldsolid;

		// if it is still inside the pusher, block
		if( SV_TestEntityPosition( check, NULL ) && block )
		{	
			if( !SV_CanBlock( check ))
				continue;

			pusher->v.ltime -= movetime;

			// move back any entities we already moved
			// go backwards, so if the same entity was pushed
			// twice, it goes back to the original position
			for( p = pushed_p - 1; p >= svgame.pushed; p-- )
			{
				VectorCopy( p->origin, p->ent->v.origin );
				VectorCopy( p->angles, p->ent->v.angles );
				SV_LinkEdict( p->ent, (p->ent == check) ? true : false );
			}
			return check;
		}	
	}

	return NULL;
}
Beispiel #27
0
/*
============
SV_PushRotate

============
*/
static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
{
	int		i, e, block, oldsolid;
	matrix4x4		start_l, end_l;
	vec3_t		lmove, amove;
	sv_pushed_t	*p, *pushed_p;
	vec3_t		org, org2, temp;
	edict_t		*check;

	if( svgame.globals->changelevel || VectorIsNull( pusher->v.avelocity ))
	{
		pusher->v.ltime += movetime;
		return NULL;
	}

	for( i = 0; i < 3; i++ )
		amove[i] = pusher->v.avelocity[i] * movetime;

	// create pusher initial position
	Matrix4x4_CreateFromEntity( start_l, pusher->v.angles, pusher->v.origin, 1.0f );

	pushed_p = svgame.pushed;

	// save the pusher's original position
	pushed_p->ent = pusher;
	VectorCopy( pusher->v.origin, pushed_p->origin );
	VectorCopy( pusher->v.angles, pushed_p->angles );
	pushed_p++;
	
	// move the pusher to it's final position
	SV_AngularMove( pusher, movetime, pusher->v.friction );
	SV_LinkEdict( pusher, false );
	pusher->v.ltime += movetime;
	oldsolid = pusher->v.solid;

	// non-solid pushers can't push anything
	if( pusher->v.solid == SOLID_NOT )
		return NULL;

	// create pusher final position
	Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f );

	// see if any solid entities are inside the final position
	for( e = 1; e < svgame.numEntities; e++ )
	{
		check = EDICT_NUM( e );
		if( !SV_IsValidEdict( check ))
			continue;

		// filter movetypes to collide with
		if( !SV_CanPushed( check ))
			continue;

		pusher->v.solid = SOLID_NOT;
		block = SV_TestEntityPosition( check, pusher );
		pusher->v.solid = oldsolid;
		if( block ) continue;

		// if the entity is standing on the pusher, it will definately be moved
		if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
		{
			if( check->v.absmin[0] >= pusher->v.absmax[0]
			|| check->v.absmin[1] >= pusher->v.absmax[1]
			|| check->v.absmin[2] >= pusher->v.absmax[2]
			|| check->v.absmax[0] <= pusher->v.absmin[0]
			|| check->v.absmax[1] <= pusher->v.absmin[1]
			|| check->v.absmax[2] <= pusher->v.absmin[2] )
				continue;

			// see if the ent's bbox is inside the pusher's final position
			if( !SV_TestEntityPosition( check, NULL ))
				continue;
		}

		// save original position of contacted entity
		pushed_p->ent = check;
		VectorCopy( check->v.origin, pushed_p->origin );
		VectorCopy( check->v.angles, pushed_p->angles );
		pushed_p->fixangle = check->v.fixangle;
		pushed_p++;

		// calculate destination position
		if( check->v.movetype == MOVETYPE_PUSHSTEP || check->v.movetype == MOVETYPE_STEP )
			VectorAverage( check->v.absmin, check->v.absmax, org );
		else VectorCopy( check->v.origin, org );

		Matrix4x4_VectorITransform( start_l, org, temp );
		Matrix4x4_VectorTransform( end_l, temp, org2 );
		VectorSubtract( org2, org, lmove );

		// i can't clear FL_ONGROUND in all cases because many bad things may be happen
		if( check->v.movetype != MOVETYPE_WALK )
		{
			if( lmove[2] != 0.0f ) check->v.flags &= ~FL_ONGROUND;
			if( lmove[2] < 0.0f && !pusher->v.dmg )
				lmove[2] = 0.0f; // let's the free falling
		}

		// try moving the contacted entity 
		pusher->v.solid = SOLID_NOT;
		SV_PushEntity( check, lmove, amove, &block );
		pusher->v.solid = oldsolid;

		// pushed entity blocked by wall
		if( block && check->v.movetype != MOVETYPE_WALK )
			check->v.flags &= ~FL_ONGROUND;

		// if it is still inside the pusher, block
		if( SV_TestEntityPosition( check, NULL ) && block )
		{	
			if( !SV_CanBlock( check ))
				continue;

			pusher->v.ltime -= movetime;

			// move back any entities we already moved
			// go backwards, so if the same entity was pushed
			// twice, it goes back to the original position
			for( p = pushed_p - 1; p >= svgame.pushed; p-- )
			{
				VectorCopy( p->origin, p->ent->v.origin );
				VectorCopy( p->angles, p->ent->v.angles );
				SV_LinkEdict( p->ent, (p->ent == check) ? true : false );
				p->ent->v.fixangle = p->fixangle;
			}
			return check;
		}
	}

	return NULL;
}
Beispiel #28
0
void
PR_ExecuteProgram (progs_t *pr, func_t fnum)
{
	dstatement_t *st;
	dfunction_t *f, *newf;
	edict_t    *ed;
	int         exitdepth;
	eval_t     *ptr;
	int         profile, startprofile;

	if (!fnum || fnum >= pr->progs->numfunctions) {
		if (pr->pr_global_struct->self)
			ED_Print (pr, PROG_TO_EDICT (pr, pr->pr_global_struct->self));
		SV_Error ("PR_ExecuteProgram: NULL function");
	}

	f = &pr->pr_functions[fnum];

	pr->pr_trace = false;

// make a stack frame
	exitdepth = pr->pr_depth;

	st = &pr->pr_statements[PR_EnterFunction (pr, f)];
	startprofile = profile = 0;

	while (1) {
		st++;
		if (++profile > 1000000)		// LordHavoc: increased runaway loop
			// limit 10x
		{
			pr->pr_xstatement = st - pr->pr_statements;
			PR_RunError (pr, "runaway loop error");
		}

		if (pr->pr_trace)
			PR_PrintStatement (pr, st);

		switch (st->op) {
			case OP_ADD_F:
				OPC->_float = OPA->_float + OPB->_float;
				break;
			case OP_ADD_V:
				OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
				OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
				OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
				break;
			case OP_SUB_F:
				OPC->_float = OPA->_float - OPB->_float;
				break;
			case OP_SUB_V:
				OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
				OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
				OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
				break;
			case OP_MUL_F:
				OPC->_float = OPA->_float * OPB->_float;
				break;
			case OP_MUL_V:
				OPC->_float =
					OPA->vector[0] * OPB->vector[0] +
					OPA->vector[1] * OPB->vector[1] +
					OPA->vector[2] * OPB->vector[2];
				break;
			case OP_MUL_FV:
				OPC->vector[0] = OPA->_float * OPB->vector[0];
				OPC->vector[1] = OPA->_float * OPB->vector[1];
				OPC->vector[2] = OPA->_float * OPB->vector[2];
				break;
			case OP_MUL_VF:
				OPC->vector[0] = OPB->_float * OPA->vector[0];
				OPC->vector[1] = OPB->_float * OPA->vector[1];
				OPC->vector[2] = OPB->_float * OPA->vector[2];
				break;
			case OP_DIV_F:
				OPC->_float = OPA->_float / OPB->_float;
				break;
			case OP_BITAND:
				OPC->_float = (int) OPA->_float & (int) OPB->_float;
				break;
			case OP_BITOR:
				OPC->_float = (int) OPA->_float | (int) OPB->_float;
				break;
			case OP_GE:
				OPC->_float = OPA->_float >= OPB->_float;
				break;
			case OP_LE:
				OPC->_float = OPA->_float <= OPB->_float;
				break;
			case OP_GT:
				OPC->_float = OPA->_float > OPB->_float;
				break;
			case OP_LT:
				OPC->_float = OPA->_float < OPB->_float;
				break;
			case OP_AND:
				OPC->_float = OPA->_float && OPB->_float;
				break;
			case OP_OR:
				OPC->_float = OPA->_float || OPB->_float;
				break;
			case OP_NOT_F:
				OPC->_float = !OPA->_float;
				break;
			case OP_NOT_V:
				OPC->_float = VectorIsNull(OPA->vector);
				break;
			case OP_NOT_S:
				OPC->_float = !OPA->string || !*PR_GetString (pr, OPA->string);
				break;
			case OP_NOT_FNC:
				OPC->_float = !OPA->function;
				break;
			case OP_NOT_ENT:
				OPC->_float = (PROG_TO_EDICT (pr, OPA->edict) == *pr->edicts);
				break;
			case OP_EQ_F:
				OPC->_float = OPA->_float == OPB->_float;
				break;
			case OP_EQ_V:
				OPC->_float = (OPA->vector[0] == OPB->vector[0])
					&& (OPA->vector[1] == OPB->vector[1])
					&& (OPA->vector[2] == OPB->vector[2]);
				break;
			case OP_EQ_S:
				OPC->_float =
					!strcmp (PR_GetString (pr, OPA->string),
							 PR_GetString (pr, OPB->string));
				break;
			case OP_EQ_E:
				OPC->_float = OPA->_int == OPB->_int;
				break;
			case OP_EQ_FNC:
				OPC->_float = OPA->function == OPB->function;
				break;
			case OP_NE_F:
				OPC->_float = OPA->_float != OPB->_float;
				break;
			case OP_NE_V:
				OPC->_float = (OPA->vector[0] != OPB->vector[0])
					|| (OPA->vector[1] != OPB->vector[1])
					|| (OPA->vector[2] != OPB->vector[2]);
				break;
			case OP_NE_S:
				OPC->_float =
					strcmp (PR_GetString (pr, OPA->string),
							PR_GetString (pr, OPB->string));
				break;
			case OP_NE_E:
				OPC->_float = OPA->_int != OPB->_int;
				break;
			case OP_NE_FNC:
				OPC->_float = OPA->function != OPB->function;
				break;

				// ==================
			case OP_STORE_F:
			case OP_STORE_ENT:
			case OP_STORE_FLD:			// integers
			case OP_STORE_S:
			case OP_STORE_FNC:			// pointers
				OPB->_int = OPA->_int;
				break;
			case OP_STORE_V:
				OPB->vector[0] = OPA->vector[0];
				OPB->vector[1] = OPA->vector[1];
				OPB->vector[2] = OPA->vector[2];
				break;

			case OP_STOREP_F:
			case OP_STOREP_ENT:
			case OP_STOREP_FLD:		// integers
			case OP_STOREP_S:
			case OP_STOREP_FNC:		// pointers
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int + 4 > pr->pr_edictareasize)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to write to an out of bounds edict\n");
					return;
				}
				if (pr_boundscheck->int_val && (OPB->_int % pr->pr_edict_size <
												((byte *) & (*pr->edicts)->v -
												 (byte *) *pr->edicts))) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to write to an engine edict field\n");
					return;
				}
				ptr = (eval_t *) ((byte *) *pr->edicts + OPB->_int);
				ptr->_int = OPA->_int;
				break;
			case OP_STOREP_V:
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int + 12 > pr->pr_edictareasize)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to write to an out of bounds edict\n");
					return;
				}
				ptr = (eval_t *) ((byte *) *pr->edicts + OPB->_int);
				ptr->vector[0] = OPA->vector[0];
				ptr->vector[1] = OPA->vector[1];
				ptr->vector[2] = OPA->vector[2];
				break;
			case OP_ADDRESS:
				if (pr_boundscheck->int_val
					&& (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to address an out of bounds edict\n");
					return;
				}
				if (pr_boundscheck->int_val
					&& (OPA->edict == 0 && pr->null_bad)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError (pr, "assignment to world entity");
					return;
				}
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int >= pr->progs->entityfields)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to address an invalid field in an edict\n");
					return;
				}
				ed = PROG_TO_EDICT (pr, OPA->edict);
				OPC->_int =
					(byte *) ((int *) &ed->v + OPB->_int) - (byte *) *pr->edicts;
				break;
			case OP_LOAD_F:
			case OP_LOAD_FLD:
			case OP_LOAD_ENT:
			case OP_LOAD_S:
			case OP_LOAD_FNC:
				if (pr_boundscheck->int_val
					&& (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an out of bounds edict number\n");
					return;
				}
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int >= pr->progs->entityfields)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an invalid field in an edict\n");
					return;
				}
				ed = PROG_TO_EDICT (pr, OPA->edict);
				OPC->_int = ((eval_t *) ((int *) &ed->v + OPB->_int))->_int;
				break;
			case OP_LOAD_V:
				if (pr_boundscheck->int_val
					&& (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an out of bounds edict number\n");
					return;
				}
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int + 2 >= pr->progs->entityfields)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an invalid field in an edict\n");
					return;
				}
				ed = PROG_TO_EDICT (pr, OPA->edict);
				OPC->vector[0] =
					((eval_t *) ((int *) &ed->v + OPB->_int))->vector[0];
				OPC->vector[1] =
					((eval_t *) ((int *) &ed->v + OPB->_int))->vector[1];
				OPC->vector[2] =
					((eval_t *) ((int *) &ed->v + OPB->_int))->vector[2];
				break;
				// ==================
			case OP_IFNOT:
				if (!OPA->_int)
					st += st->b - 1;	// offset the s++
				break;
			case OP_IF:
				if (OPA->_int)
					st += st->b - 1;	// offset the s++
				break;
			case OP_GOTO:
				st += st->a - 1;		// offset the s++
				break;
			case OP_CALL0:
			case OP_CALL1:
			case OP_CALL2:
			case OP_CALL3:
			case OP_CALL4:
			case OP_CALL5:
			case OP_CALL6:
			case OP_CALL7:
			case OP_CALL8:
				pr->pr_xfunction->profile += profile - startprofile;
				startprofile = profile;
				pr->pr_xstatement = st - pr->pr_statements;
				pr->pr_argc = st->op - OP_CALL0;
				if (!OPA->function)
					PR_RunError (pr, "NULL function");
				newf = &pr->pr_functions[OPA->function];
				if (newf->first_statement < 0) {	// negative
					// statements are
					// built in functions
					int         i = -newf->first_statement;

					if (i >= pr_numbuiltins)
						PR_RunError (pr, "Bad builtin call number");
					pr_builtins[i] (pr);
					break;
				}

				st = &pr->pr_statements[PR_EnterFunction (pr, newf)];
				break;
			case OP_DONE:
			case OP_RETURN:
				pr->pr_globals[OFS_RETURN] = pr->pr_globals[(unsigned short) st->a];
				pr->pr_globals[OFS_RETURN + 1] =
					pr->pr_globals[(unsigned short) st->a + 1];
				pr->pr_globals[OFS_RETURN + 2] =
					pr->pr_globals[(unsigned short) st->a + 2];
				st = &pr->pr_statements[PR_LeaveFunction (pr)];
				if (pr->pr_depth == exitdepth)
					return;				// all done
				break;
			case OP_STATE:
				ed = PROG_TO_EDICT (pr, pr->pr_global_struct->self);
				ed->v.v.nextthink = pr->pr_global_struct->time + 0.1;
				ed->v.v.frame = OPA->_float;
				ed->v.v.think = OPB->function;
				break;
// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
/*
			case OP_ADD_I:
				OPC->_int = OPA->_int + OPB->_int;
				break;
			case OP_ADD_IF:
				OPC->_int = OPA->_int + (int) OPB->_float;
				break;
			case OP_ADD_FI:
				OPC->_float = OPA->_float + (float) OPB->_int;
				break;
			case OP_SUB_I:
				OPC->_int = OPA->_int - OPB->_int;
				break;
			case OP_SUB_IF:
				OPC->_int = OPA->_int - (int) OPB->_float;
				break;
			case OP_SUB_FI:
				OPC->_float = OPA->_float - (float) OPB->_int;
				break;
			case OP_MUL_I:
				OPC->_int = OPA->_int * OPB->_int;
				break;
			case OP_MUL_IF:
				OPC->_int = OPA->_int * (int) OPB->_float;
				break;
			case OP_MUL_FI:
				OPC->_float = OPA->_float * (float) OPB->_int;
				break;
			case OP_MUL_VI:
				OPC->vector[0] = (float) OPB->_int * OPA->vector[0];
				OPC->vector[1] = (float) OPB->_int * OPA->vector[1];
				OPC->vector[2] = (float) OPB->_int * OPA->vector[2];
				break;
			case OP_DIV_VF:
				{
					float       temp = 1.0f / OPB->_float;

					OPC->vector[0] = temp * OPA->vector[0];
					OPC->vector[1] = temp * OPA->vector[1];
					OPC->vector[2] = temp * OPA->vector[2];
				}
				break;
			case OP_DIV_I:
				OPC->_int = OPA->_int / OPB->_int;
				break;
			case OP_DIV_IF:
				OPC->_int = OPA->_int / (int) OPB->_float;
				break;
			case OP_DIV_FI:
				OPC->_float = OPA->_float / (float) OPB->_int;
				break;
			case OP_CONV_IF:
				OPC->_float = OPA->_int;
				break;
			case OP_CONV_FI:
				OPC->_int = OPA->_float;
				break;
			case OP_BITAND_I:
				OPC->_int = OPA->_int & OPB->_int;
				break;
			case OP_BITOR_I:
				OPC->_int = OPA->_int | OPB->_int;
				break;
			case OP_BITAND_IF:
				OPC->_int = OPA->_int & (int) OPB->_float;
				break;
			case OP_BITOR_IF:
				OPC->_int = OPA->_int | (int) OPB->_float;
				break;
			case OP_BITAND_FI:
				OPC->_float = (int) OPA->_float & OPB->_int;
				break;
			case OP_BITOR_FI:
				OPC->_float = (int) OPA->_float | OPB->_int;
				break;
			case OP_GE_I:
				OPC->_float = OPA->_int >= OPB->_int;
				break;
			case OP_LE_I:
				OPC->_float = OPA->_int <= OPB->_int;
				break;
			case OP_GT_I:
				OPC->_float = OPA->_int > OPB->_int;
				break;
			case OP_LT_I:
				OPC->_float = OPA->_int < OPB->_int;
				break;
			case OP_AND_I:
				OPC->_float = OPA->_int && OPB->_int;
				break;
			case OP_OR_I:
				OPC->_float = OPA->_int || OPB->_int;
				break;
			case OP_GE_IF:
				OPC->_float = (float) OPA->_int >= OPB->_float;
				break;
			case OP_LE_IF:
				OPC->_float = (float) OPA->_int <= OPB->_float;
				break;
			case OP_GT_IF:
				OPC->_float = (float) OPA->_int > OPB->_float;
				break;
			case OP_LT_IF:
				OPC->_float = (float) OPA->_int < OPB->_float;
				break;
			case OP_AND_IF:
				OPC->_float = (float) OPA->_int && OPB->_float;
				break;
			case OP_OR_IF:
				OPC->_float = (float) OPA->_int || OPB->_float;
				break;
			case OP_GE_FI:
				OPC->_float = OPA->_float >= (float) OPB->_int;
				break;
			case OP_LE_FI:
				OPC->_float = OPA->_float <= (float) OPB->_int;
				break;
			case OP_GT_FI:
				OPC->_float = OPA->_float > (float) OPB->_int;
				break;
			case OP_LT_FI:
				OPC->_float = OPA->_float < (float) OPB->_int;
				break;
			case OP_AND_FI:
				OPC->_float = OPA->_float && (float) OPB->_int;
				break;
			case OP_OR_FI:
				OPC->_float = OPA->_float || (float) OPB->_int;
				break;
			case OP_NOT_I:
				OPC->_float = !OPA->_int;
				break;
			case OP_EQ_I:
				OPC->_float = OPA->_int == OPB->_int;
				break;
			case OP_EQ_IF:
				OPC->_float = (float) OPA->_int == OPB->_float;
				break;
			case OP_EQ_FI:
				OPC->_float = OPA->_float == (float) OPB->_int;
				break;
			case OP_NE_I:
				OPC->_float = OPA->_int != OPB->_int;
				break;
			case OP_NE_IF:
				OPC->_float = (float) OPA->_int != OPB->_float;
				break;
			case OP_NE_FI:
				OPC->_float = OPA->_float != (float) OPB->_int;
				break;
			case OP_STORE_I:
				OPB->_int = OPA->_int;
				break;
			case OP_STOREP_I:
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int + 4 > pr->pr_edictareasize)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to write to an out of bounds edict\n");
					return;
				}
				if (pr_boundscheck->int_val
					&& (OPB->_int % pr->pr_edict_size <
						((byte *) & (*pr->edicts)->v - (byte *) *pr->edicts))) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to write to an engine edict field\n");
					return;
				}
				ptr = (eval_t *) ((byte *) *pr->edicts + OPB->_int);
				ptr->_int = OPA->_int;
				break;
			case OP_LOAD_I:
				if (pr_boundscheck->int_val
					&& (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an out of bounds edict number\n");
					return;
				}
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int >= pr->progs->entityfields)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an invalid field in an edict\n");
					return;
				}
				ed = PROG_TO_EDICT (pr, OPA->edict);
				OPC->_int = ((eval_t *) ((int *) &ed->v + OPB->_int))->_int;
				break;

			case OP_GSTOREP_I:
			case OP_GSTOREP_F:
			case OP_GSTOREP_ENT:
			case OP_GSTOREP_FLD:	// integers
			case OP_GSTOREP_S:
			case OP_GSTOREP_FNC:	// pointers
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int >= pr->pr_globaldefs)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to write to an invalid indexed global\n");
					return;
				}
				pr->pr_globals[OPB->_int] = OPA->_float;
				break;
			case OP_GSTOREP_V:
				if (pr_boundscheck->int_val
					&& (OPB->_int < 0 || OPB->_int + 2 >= pr->pr_globaldefs)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to write to an invalid indexed global\n");
					return;
				}
				pr->pr_globals[OPB->_int] = OPA->vector[0];
				pr->pr_globals[OPB->_int + 1] = OPA->vector[1];
				pr->pr_globals[OPB->_int + 2] = OPA->vector[2];
				break;

			case OP_GADDRESS:
				i = OPA->_int + (int) OPB->_float;
				if (pr_boundscheck->int_val
					&& (i < 0 || i >= pr->pr_globaldefs)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to address an out of bounds global\n");
					return;
				}
				OPC->_float = pr->pr_globals[i];
				break;

			case OP_GLOAD_I:
			case OP_GLOAD_F:
			case OP_GLOAD_FLD:
			case OP_GLOAD_ENT:
			case OP_GLOAD_S:
			case OP_GLOAD_FNC:
				if (pr_boundscheck->int_val
					&& (OPA->_int < 0 || OPA->_int >= pr->pr_globaldefs)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an invalid indexed global\n");
					return;
				}
				OPC->_float = pr->pr_globals[OPA->_int];
				break;

			case OP_GLOAD_V:
				if (pr_boundscheck->int_val
					&& (OPA->_int < 0 || OPA->_int + 2 >= pr->pr_globaldefs)) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs attempted to read an invalid indexed global\n");
					return;
				}
				OPC->vector[0] = pr->pr_globals[OPA->_int];
				OPC->vector[1] = pr->pr_globals[OPA->_int + 1];
				OPC->vector[2] = pr->pr_globals[OPA->_int + 2];
				break;

			case OP_BOUNDCHECK:
				if (OPA->_int < 0 || OPA->_int >= st->b) {
					pr->pr_xstatement = st - pr->pr_statements;
					PR_RunError
						(pr, "Progs boundcheck failed at line number %d, value is < 0 or >= %d\n",
						 st->b, st->c);
					return;
				}
				break;

*/
			default:
				pr->pr_xstatement = st - pr->pr_statements;
				PR_RunError (pr, "Bad opcode %i", st->op);
		}
	}
}