bool	PM_SlideMove_Helo() {
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;

	numbumps = 4;

	VectorCopy (pm->ps->velocity, primal_velocity);

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane ) {
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[0] );
	} else {
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[numplanes] );
	numplanes++;

	for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
		VectorMA(pm->ps->origin, time_left, pm->ps->velocity, end );			// calculate position we are trying to move to

		// see if we can make it there
		pm->trace ( &trace, 
					pm->ps->origin, 
					pm->mins, 
					pm->maxs, 
					end, 
					pm->ps->clientNum, 
					pm->tracemask,
					false);

		if (trace.allsolid) {

			pm->trace ( &trace, 
					pm->ps->origin, 
					0, 
					0, 
					end, 
					pm->ps->clientNum, 
					pm->tracemask,
					false);

			if( trace.allsolid ) {
				// entity is completely trapped in another solid
				pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
				return true;
			}
		}

		if (trace.fraction > 0) {
			// actually covered some distance
			VectorCopy (trace.endpos, pm->ps->origin);
		}

		if (trace.fraction == 1) {
			 break;		// moved the entire distance
		}

		// save entity for contact
		if(	trace.entityNum != ENTITYNUM_WORLD ||
			pm->ps->stats[STAT_HEALTH] <= 0 ||
			(trace.entityNum == ENTITYNUM_WORLD &&
//				!(trace.surfaceFlags & SURF_NOIMPACT) &&
			!(trace.surfaceFlags & SURF_SKY)) ) {
			PM_AddTouchEnt_Helo( trace.entityNum );
		}

		time_left -= time_left * trace.fraction;

		if (numplanes >= MAX_CLIP_PLANES) {
			// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return true;
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		for ( i = 0 ; i < numplanes ; i++ ) {
			if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
				VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
				break;
			}
		}
		if ( i < numplanes ) {
			continue;
		}
		VectorCopy (trace.plane.normal, planes[numplanes]);
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) {
			into = DotProduct( pm->ps->velocity, planes[i] );
			if ( into >= 0.1 ) {
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) {
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

			// slide along the plane
			PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

			// see if there is a second plane that the New move enters
			for ( j = 0 ; j < numplanes ; j++ ) {
				if ( j == i ) {
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the New move enters
				for ( k = 0 ; k < numplanes ; k++ ) {
					if ( k == i || k == j ) {
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a tripple plane interaction
					VectorClear( pm->ps->velocity );
					return true;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time ) {
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

	return ( bumpcount != 0 );
	return 0;
}
Esempio n. 2
0
/*
=================
R_MarkFragments

=================
*/
int R_MarkFragments(int numPoints, const vec3_t * points, const vec3_t projection,
					int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t * fragmentBuffer)
{
	int             numsurfaces, numPlanes;
	int             i, j, k, m, n;
	surfaceType_t  *surfaces[64];
	vec3_t          mins, maxs;
	int             returnedFragments;
	int             returnedPoints;
	vec3_t          normals[MAX_VERTS_ON_POLY + 2];
	float           dists[MAX_VERTS_ON_POLY + 2];
	vec3_t          clipPoints[2][MAX_VERTS_ON_POLY];
	int             numClipPoints;
	float          *v;
	srfSurfaceFace_t *face;
	srfGridMesh_t  *cv;
	srfTriangles_t *trisurf;
	srfVert_t      *dv;
	srfTriangle_t  *tri;
	vec3_t          normal;
	vec3_t          projectionDir;
	vec3_t          v1, v2;

	//increment view count for double check prevention
	tr.viewCountNoReset++;

	//
	VectorNormalize2(projection, projectionDir);
	// find all the brushes that are to be considered
	ClearBounds(mins, maxs);
	for(i = 0; i < numPoints; i++)
	{
		vec3_t          temp;

		AddPointToBounds(points[i], mins, maxs);
		VectorAdd(points[i], projection, temp);
		AddPointToBounds(temp, mins, maxs);
		// make sure we get all the leafs (also the one(s) in front of the hit surface)
		VectorMA(points[i], -20, projectionDir, temp);
		AddPointToBounds(temp, mins, maxs);
	}

	if(numPoints > MAX_VERTS_ON_POLY)
		numPoints = MAX_VERTS_ON_POLY;
	// create the bounding planes for the to be projected polygon
	for(i = 0; i < numPoints; i++)
	{
		VectorSubtract(points[(i + 1) % numPoints], points[i], v1);
		VectorAdd(points[i], projection, v2);
		VectorSubtract(points[i], v2, v2);
		CrossProduct(v1, v2, normals[i]);
		VectorNormalizeFast(normals[i]);
		dists[i] = DotProduct(normals[i], points[i]);
	}
	// add near and far clipping planes for projection
	VectorCopy(projectionDir, normals[numPoints]);
	dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
	VectorCopy(projectionDir, normals[numPoints + 1]);
	VectorInverse(normals[numPoints + 1]);
	dists[numPoints + 1] = DotProduct(normals[numPoints + 1], points[0]) - 20;
	numPlanes = numPoints + 2;

	numsurfaces = 0;
	R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
	//assert(numsurfaces <= 64);
	//assert(numsurfaces != 64);

	returnedPoints = 0;
	returnedFragments = 0;

	for(i = 0; i < numsurfaces; i++)
	{
		if(*surfaces[i] == SF_GRID)
		{
			cv = (srfGridMesh_t *) surfaces[i];
			for(m = 0; m < cv->height - 1; m++)
			{
				for(n = 0; n < cv->width - 1; n++)
				{
					// We triangulate the grid and chop all triangles within
					// the bounding planes of the to be projected polygon.
					// LOD is not taken into account, not such a big deal though.
					//
					// It's probably much nicer to chop the grid itself and deal
					// with this grid as a normal SF_GRID surface so LOD will
					// be applied. However the LOD of that chopped grid must
					// be synced with the LOD of the original curve.
					// One way to do this; the chopped grid shares vertices with
					// the original curve. When LOD is applied to the original
					// curve the unused vertices are flagged. Now the chopped curve
					// should skip the flagged vertices. This still leaves the
					// problems with the vertices at the chopped grid edges.
					//
					// To avoid issues when LOD applied to "hollow curves" (like
					// the ones around many jump pads) we now just add a 2 unit
					// offset to the triangle vertices.
					// The offset is added in the vertex normal vector direction
					// so all triangles will still fit together.
					// The 2 unit offset should avoid pretty much all LOD problems.

					numClipPoints = 3;

					dv = cv->verts + m * cv->width + n;

					VectorCopy(dv[0].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalizeFast(normal);
					if(DotProduct(normal, projectionDir) < -0.1)
					{
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
										   numPlanes, normals, dists,
										   maxPoints, pointBuffer,
										   maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);

						if(returnedFragments == maxFragments)
						{
							return returnedFragments;	// not enough space for more fragments
						}
					}

					VectorCopy(dv[1].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[cv->width + 1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width + 1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalizeFast(normal);
					if(DotProduct(normal, projectionDir) < -0.05)
					{
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
										   numPlanes, normals, dists,
										   maxPoints, pointBuffer,
										   maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);

						if(returnedFragments == maxFragments)
						{
							return returnedFragments;	// not enough space for more fragments
						}
					}
				}
			}
		}
		else if(*surfaces[i] == SF_FACE)
		{
			face = (srfSurfaceFace_t *) surfaces[i];

			// check the normal of this face
			if(DotProduct(face->plane.normal, projectionDir) > -0.5)
			{
				continue;
			}

			for(k = 0, tri = face->triangles; k < face->numTriangles; k++, tri++)
			{
				for(j = 0; j < 3; j++)
				{
					v = face->verts[tri->indexes[j]].xyz;
					VectorMA(v, MARKER_OFFSET, face->plane.normal, clipPoints[0][j]);
				}

				/*
				   VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
				   VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
				   CrossProduct(v1, v2, normal);
				   VectorNormalize(normal);
				   if (DotProduct(normal, projectionDir) > -0.5) continue;
				   */

				// add the fragments of this face
				R_AddMarkFragments(3, clipPoints,
								   numPlanes, normals, dists,
								   maxPoints, pointBuffer,
								   maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
				if(returnedFragments == maxFragments)
				{
					return returnedFragments;	// not enough space for more fragments
				}
			}
		}
		else if (*surfaces[i] == SF_TRIANGLES && !r_noMarksOnTrisurfs->integer)
		{
			trisurf = (srfTriangles_t *) surfaces[i];

			for(k = 0, tri = trisurf->triangles; k < trisurf->numTriangles; k++, tri++)
			{
				for(j = 0; j < 3; j++)
				{
					VectorCopy (trisurf->verts[tri->indexes[j]].xyz, clipPoints[0][j]);
				}

				/*
				   VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
				   VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
				   CrossProduct(v1, v2, normal);
				   VectorNormalize(normal);
				   if (DotProduct(normal, projectionDir) > -0.5) continue;
				   */

				// add the fragments of this face
				R_AddMarkFragments(3, clipPoints,
								   numPlanes, normals, dists,
								   maxPoints, pointBuffer,
								   maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
				if(returnedFragments == maxFragments)
				{
					return returnedFragments;	// not enough space for more fragments
				}
			}
		}
	}
	return returnedFragments;
}
Esempio n. 3
0
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
					float orientation, float red, float green, float blue, float alpha,
					qboolean alphaFade, float radius, qboolean temporary, int duration ) {
	vec3_t axis[3];
	float texCoordScale;
	vec3_t originalPoints[4];
	byte colors[4];
	int i, j;
	int numFragments;
	markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
	vec5_t markPoints[MAX_MARK_POINTS];             // Ridah, made it vec5_t so it includes S/T
	vec3_t projection;
	int multMaxFragments = 1;

	if ( !cg_markTime.integer ) {
		return;
	}

	if ( radius <= 0 ) {
		// just ignore it, don't error out
		return;
//		CG_Error( "CG_ImpactMark called with <= 0 radius" );
	}

	// Ridah, if no duration, use the default
	if ( duration < 0 ) {
		if ( duration == -2 ) {
			multMaxFragments = -1;  // use original mapping
		}

//		duration = MARK_TOTAL_TIME;
		duration = cg_markTime.integer;
	}

	// create the texture axis
	VectorNormalize2( dir, axis[0] );
	PerpendicularVector( axis[1], axis[0] );
	RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
	CrossProduct( axis[0], axis[2], axis[1] );

	texCoordScale = 0.5 * 1.0 / radius;

	// create the full polygon
	for ( i = 0 ; i < 3 ; i++ ) {
		originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
		originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
		originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
		originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
	}

	// get the fragments
	//VectorScale( dir, -20, projection );
	VectorScale( dir, radius * 2, projection );
	numFragments = trap_CM_MarkFragments( (int)orientation, (void *)originalPoints,
										  projection, MAX_MARK_POINTS, (float *)&markPoints[0],
										  MAX_MARK_FRAGMENTS * multMaxFragments, markFragments );

	colors[0] = red * 255;
	colors[1] = green * 255;
	colors[2] = blue * 255;
	colors[3] = alpha * 255;

	for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
		polyVert_t  *v;
		polyVert_t verts[MAX_VERTS_ON_POLY];
		markPoly_t  *mark;
		qboolean hasST;

		// we have an upper limit on the complexity of polygons
		// that we store persistantly
		if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
			mf->numPoints = MAX_VERTS_ON_POLY;
		}
		if ( mf->numPoints < 0 ) {
			hasST = qtrue;
			mf->numPoints *= -1;
		} else {
			hasST = qfalse;
		}
		for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
			vec3_t delta;

			VectorCopy( markPoints[mf->firstPoint + j], v->xyz );

			if ( !hasST ) {
				VectorSubtract( v->xyz, origin, delta );
				v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
				v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
			} else {
				v->st[0] = markPoints[mf->firstPoint + j][3];
				v->st[1] = markPoints[mf->firstPoint + j][4];
			}

			*(int *)v->modulate = *(int *)colors;
		}

		// if it is a temporary (shadow) mark, add it immediately and forget about it
		if ( temporary ) {
			trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
			continue;
		}

		// otherwise save it persistantly
		mark = CG_AllocMark( cg.time + duration );
		mark->time = cg.time;
		mark->alphaFade = alphaFade;
		mark->markShader = markShader;
		mark->poly.numVerts = mf->numPoints;
		mark->color[0] = red;
		mark->color[1] = green;
		mark->color[2] = blue;
		mark->color[3] = alpha;
		mark->duration = duration;
		memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
	}
}
Esempio n. 4
0
/*
=================
R_SetupEntityLightingGrid

=================
*/
static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
	vec3_t	lightOrigin;
	int		pos[3];
	int		i, j;
	byte	*gridData;
	float	frac[3];
	int		gridStep[3];
	vec3_t	direction;
	float	totalFactor;

	if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
		// seperate lightOrigins are needed so an object that is
		// sinking into the ground can still be lit, and so
		// multi-part models can be lit identically
		VectorCopy( ent->e.lightingOrigin, lightOrigin );
	} else {
		VectorCopy( ent->e.origin, lightOrigin );
	}

	VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
	for ( i = 0 ; i < 3 ; i++ ) {
		float	v;

		v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
		pos[i] = floor( v );
		frac[i] = v - pos[i];
		if ( pos[i] < 0 ) {
			pos[i] = 0;
		} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
			pos[i] = tr.world->lightGridBounds[i] - 1;
		}
	}

	VectorClear( ent->ambientLight );
	VectorClear( ent->directedLight );
	VectorClear( direction );

	assert( tr.world->lightGridData ); // NULL with -nolight maps

	// trilerp the light value
	gridStep[0] = 8;
	gridStep[1] = 8 * tr.world->lightGridBounds[0];
	gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
	gridData = tr.world->lightGridData + pos[0] * gridStep[0]
		+ pos[1] * gridStep[1] + pos[2] * gridStep[2];

	totalFactor = 0;
	for ( i = 0 ; i < 8 ; i++ ) {
		float	factor;
		byte	*data;
		int		lat, lng;
		vec3_t	normal;
		#if idppc
		float d0, d1, d2, d3, d4, d5;
		#endif
		factor = 1.0;
		data = gridData;
		for ( j = 0 ; j < 3 ; j++ ) {
			if ( i & (1<<j) ) {
				factor *= frac[j];
				data += gridStep[j];
			} else {
				factor *= (1.0f - frac[j]);
			}
		}

		if ( !(data[0]+data[1]+data[2]) ) {
			continue;	// ignore samples in walls
		}
		totalFactor += factor;
		#if idppc
		d0 = data[0]; d1 = data[1]; d2 = data[2];
		d3 = data[3]; d4 = data[4]; d5 = data[5];

		ent->ambientLight[0] += factor * d0;
		ent->ambientLight[1] += factor * d1;
		ent->ambientLight[2] += factor * d2;

		ent->directedLight[0] += factor * d3;
		ent->directedLight[1] += factor * d4;
		ent->directedLight[2] += factor * d5;
		#else
		ent->ambientLight[0] += factor * data[0];
		ent->ambientLight[1] += factor * data[1];
		ent->ambientLight[2] += factor * data[2];

		ent->directedLight[0] += factor * data[3];
		ent->directedLight[1] += factor * data[4];
		ent->directedLight[2] += factor * data[5];
		#endif
		lat = data[7];
		lng = data[6];
		lat *= (FUNCTABLE_SIZE/256);
		lng *= (FUNCTABLE_SIZE/256);

		// decode X as cos( lat ) * sin( long )
		// decode Y as sin( lat ) * sin( long )
		// decode Z as cos( long )

		normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
		normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
		normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];

		VectorMA( direction, factor, normal, direction );
	}

	if ( totalFactor > 0 && totalFactor < 0.99 ) {
		totalFactor = 1.0f / totalFactor;
		VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
		VectorScale( ent->directedLight, totalFactor, ent->directedLight );
	}

	VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
	VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );

	VectorNormalize2( direction, ent->lightDir );
}
Esempio n. 5
0
void CG_ImpactMark( qhandle_t markShader, const vector3 *origin, const vector3 *dir, 
				   float orientation, float red, float green, float blue, float alpha,
				   qboolean alphaFade, float radius, qboolean temporary ) {
	vector3			axis[3];
	float			texCoordScale;
	vector3			originalPoints[4];
	byte			colors[4];
	int				i, j;
	int				numFragments;
	markFragment_t	markFragments[MAX_MARK_FRAGMENTS], *mf;
	vector3			markPoints[MAX_MARK_POINTS];
	vector3			projection;

	assert(markShader);

	if ( !cg_marks.integer ) {
		return;
	}
	else if (cg_marks.integer == 2)
	{
		trap->R_AddDecalToScene(markShader, origin, dir, orientation, red, green, blue, alpha,
			alphaFade, radius, temporary);
		return;
	}

	if ( radius <= 0 ) {
		trap->Error( ERR_DROP, "CG_ImpactMark called with <= 0 radius" );
	}

	//if ( markTotal >= MAX_MARK_POLYS ) {
	//	return;
	//}

	// create the texture axis
	VectorNormalize2( dir, &axis[0] );
	PerpendicularVector( &axis[1], &axis[0] );
	RotatePointAroundVector( &axis[2], &axis[0], &axis[1], orientation );
	CrossProduct( &axis[0], &axis[2], &axis[1] );

	texCoordScale = 0.5 * 1.0 / radius;

	// create the full polygon
	for ( i = 0 ; i < 3 ; i++ ) {
		originalPoints[0].data[i] = origin->data[i] - radius * axis[1].data[i] - radius * axis[2].data[i];
		originalPoints[1].data[i] = origin->data[i] + radius * axis[1].data[i] - radius * axis[2].data[i];
		originalPoints[2].data[i] = origin->data[i] + radius * axis[1].data[i] + radius * axis[2].data[i];
		originalPoints[3].data[i] = origin->data[i] - radius * axis[1].data[i] + radius * axis[2].data[i];
	}

	// get the fragments
	VectorScale( dir, -20, &projection );
	numFragments = trap->R_MarkFragments( 4, originalPoints,
					&projection, MAX_MARK_POINTS, &markPoints[0],
					MAX_MARK_FRAGMENTS, markFragments );

	colors[0] = red * 255;
	colors[1] = green * 255;
	colors[2] = blue * 255;
	colors[3] = alpha * 255;

	for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
		polyVert_t	*v;
		polyVert_t	verts[MAX_VERTS_ON_POLY];
		markPoly_t	*mark;

		// we have an upper limit on the complexity of polygons
		// that we store persistantly
		if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
			mf->numPoints = MAX_VERTS_ON_POLY;
		}
		for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
			vector3		delta;

			VectorCopy( &markPoints[mf->firstPoint + j], &v->xyz );

			VectorSubtract( &v->xyz, origin, &delta );
			v->st[0] = 0.5 + DotProduct( &delta, &axis[1] ) * texCoordScale;
			v->st[1] = 0.5 + DotProduct( &delta, &axis[2] ) * texCoordScale;
			*(int *)v->modulate = *(int *)colors;
		}

		// if it is a temporary (shadow) mark, add it immediately and forget about it
		if ( temporary ) {
			trap->R_AddPolysToScene( markShader, mf->numPoints, verts, 1 );
			continue;
		}

		// otherwise save it persistantly
		mark = CG_AllocMark();
		mark->time = cg.time;
		mark->alphaFade = alphaFade;
		mark->markShader = markShader;
		mark->poly.numVerts = mf->numPoints;
		mark->color[0] = red;
		mark->color[1] = green;
		mark->color[2] = blue;
		mark->color[3] = alpha;
		memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
		markTotal++;
	}
}
Esempio n. 6
0
void FlameJunc_think__target_flamethrower( edict_t *self )
{
	vec3_t	oldorg;
	trace_t tr;

	VectorCopy( self->s.origin, oldorg );

	// move it
	VectorMA( self->s.origin, FRAMETIME, self->velocity, self->s.origin );

	tr = gi.trace( oldorg, jmins, jmaxs, self->s.origin, NULL, MASK_SOLID );

	if (tr.fraction < 1)
	{	// copied from ClipVelocity()
		#define	STOP_EPSILON	0.1

		float	backoff;
		float	change;
		int		i;

		// go through alpha surfaces
		if (tr.contents & MASK_ALPHA)
		{
			vec3_t	start, unitvel;
			float	maxdist, dist;

			if (tr.startsolid)
				maxdist = VectorLength( self->velocity ) * FRAMETIME;
			else
				maxdist = VectorLength( self->velocity ) * (1 - tr.fraction) * FRAMETIME;

			VectorNormalize2( self->velocity, unitvel );

			VectorCopy( tr.endpos, start );
			dist = 4;
			VectorMA( start, dist, unitvel, start );
			tr.startsolid = 1;		// to get us started

			while ((dist < maxdist) && tr.startsolid && (tr.contents & MASK_ALPHA))
			{
				tr = gi.trace ( start, jmins, jmaxs, self->s.origin, NULL, MASK_SOLID );

				dist += 4;
				VectorMA( start, 4, unitvel, start );
			}

			if (dist >= maxdist || tr.fraction == 1)
			{
				tr.fraction = 1;
				goto skip_clip;
			}
		}

		backoff = DotProduct (self->velocity, tr.plane.normal) * 1.5;	//slide

		for (i=0 ; i<3 ; i++)
		{
			change = tr.plane.normal[i]*backoff;
			self->velocity[i] = self->velocity[i] - change;
			if (self->velocity[i] > -STOP_EPSILON && self->velocity[i] < STOP_EPSILON)
				self->velocity[i] = 0;
		}

		VectorCopy( tr.endpos, self->s.origin );
		VectorMA( self->s.origin, 4, tr.plane.normal, self->s.origin );
		VectorNormalize2( self->velocity, self->last_step_pos );

		if (!self->acc)
		{
			// slow it down
			VectorScale( self->velocity, 0.5, self->velocity );
		}

		self->acc = true;

		if (strstr(tr.surface->name, "wood"))	// spawn some smoke
		{
			static vec3_t	last_pos;
			static float	last_time;
			vec3_t			sm_pos;

			// so we don't spawn too many sprites over each other
			if (last_time > (level.time - 0.5))
			{
				if (VectorDistance( last_pos, tr.endpos ) < 32)
					goto skip_smoke;
			}

			last_time = level.time;
			VectorCopy( tr.endpos, last_pos );

			VectorMA( tr.endpos, 16, tr.plane.normal, sm_pos );
			sm_pos[2] -= 12;

			gi.WriteByte (svc_temp_entity);
			gi.WriteByte (TE_SFXSMOKE);
			gi.WritePosition (sm_pos);
			gi.WriteByte (48);
			gi.WriteByte (0);
			gi.multicast (tr.endpos, MULTICAST_PVS);
		}

skip_smoke:;

	}

skip_clip:

	//NAV_DrawLine( self->s.old_origin, self->s.origin );

	// Now do the damage
	T_RadiusDamage_Fire( self, self->owner, self->dmg, NULL, 128);
	self->biketime = level.time;

	if (self->timestamp <= level.time)
	{
		G_FreeEdict( self );
		return;
	}

	self->nextthink = level.time + 0.1;
}
Esempio n. 7
0
void	AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
	int			i, j, k;
	float		*p, *copy;
	vec3_t		dir;
	float		d;
	int			numHullPoints, numNew;
	vec3_t		hullPoints[MAX_HULL_POINTS];
	vec3_t		newHullPoints[MAX_HULL_POINTS];
	vec3_t		hullDirs[MAX_HULL_POINTS];
	qboolean	hullSide[MAX_HULL_POINTS];
	qboolean	outside;

	if ( !*hull ) {
		*hull = CopyWinding( w );
		return;
	}

	numHullPoints = (*hull)->numpoints;
	Com_Memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );

	for ( i = 0 ; i < w->numpoints ; i++ ) {
		p = w->p[i];

		// calculate hull side vectors
		for ( j = 0 ; j < numHullPoints ; j++ ) {
			k = ( j + 1 ) % numHullPoints;

			VectorSubtract( hullPoints[k], hullPoints[j], dir );
			VectorNormalize2( dir, dir );
			CrossProduct( normal, dir, hullDirs[j] );
		}

		outside = qfalse;
		for ( j = 0 ; j < numHullPoints ; j++ ) {
			VectorSubtract( p, hullPoints[j], dir );
			d = DotProduct( dir, hullDirs[j] );
			if ( d >= ON_EPSILON ) {
				outside = qtrue;
			}
			if ( d >= -ON_EPSILON ) {
				hullSide[j] = qtrue;
			} else {
				hullSide[j] = qfalse;
			}
		}

		// if the point is effectively inside, do nothing
		if ( !outside ) {
			continue;
		}

		// find the back side to front side transition
		for ( j = 0 ; j < numHullPoints ; j++ ) {
			if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
				break;
			}
		}
		if ( j == numHullPoints ) {
			continue;
		}

		// insert the point here
		VectorCopy( p, newHullPoints[0] );
		numNew = 1;

		// copy over all points that aren't double fronts
		j = (j+1)%numHullPoints;
		for ( k = 0 ; k < numHullPoints ; k++ ) {
			if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
				continue;
			}
			copy = hullPoints[ (j+k+1) % numHullPoints ];
			VectorCopy( copy, newHullPoints[numNew] );
			numNew++;
		}

		numHullPoints = numNew;
		Com_Memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
	}

	FreeWinding( *hull );
	w = AllocWinding( numHullPoints );
	w->numpoints = numHullPoints;
	*hull = w;
	Com_Memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
}
Esempio n. 8
0
qboolean	PM_SlideMove( float gravMod ) {
    int			bumpcount, numbumps;
    vec3_t		dir;
    float		d;
    int			numplanes;
    vec3_t		normal, planes[MAX_CLIP_PLANES];
    vec3_t		primal_velocity;
    vec3_t		clipVelocity;
    int			i, j, k;
    trace_t	trace;
    vec3_t		end;
    float		time_left;
    float		into;
    vec3_t		endVelocity;
    vec3_t		endClipVelocity;
    qboolean	damageSelf = qtrue;
    int			slideMoveContents = pm->tracemask;

    if ( pm->ps->clientNum >= MAX_CLIENTS
            && !PM_ControlledByPlayer() )
    {   //a non-player client, not an NPC under player control
        if ( pml.walking //walking on the ground
                || (pm->ps->groundEntityNum != ENTITYNUM_NONE //in air
                    && PM_InSpecialJump( pm->ps->legsAnim )//in a special jump
                    && !(pm->ps->eFlags&EF_FORCE_GRIPPED)//not being gripped
                    && !(pm->ps->pm_flags&PMF_TIME_KNOCKBACK)
                    && pm->gent
                    && pm->gent->forcePushTime < level.time) )//not being pushed
        {   //
            // If we're a vehicle, ignore this if we're being driven
            if ( !pm->gent //not an game ent
                    || !pm->gent->client //not a client
                    || pm->gent->client->NPC_class != CLASS_VEHICLE//not a vehicle
                    || !pm->gent->m_pVehicle //no vehicle
                    || !pm->gent->m_pVehicle->m_pPilot//no pilot
                    || pm->gent->m_pVehicle->m_pPilot->s.number >= MAX_CLIENTS )//pilot is not the player
            {   //then treat do not enter brushes as SOLID
                slideMoveContents |= CONTENTS_BOTCLIP;
            }
        }
    }

    numbumps = 4;

    VectorCopy (pm->ps->velocity, primal_velocity);
    VectorCopy (pm->ps->velocity, endVelocity);

    if ( gravMod )
    {
        if ( !(pm->ps->eFlags&EF_FORCE_GRIPPED) && !(pm->ps->eFlags&EF_FORCE_DRAINED) )
        {
            endVelocity[2] -= pm->ps->gravity * pml.frametime * gravMod;
        }
        pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
        primal_velocity[2] = endVelocity[2];
        if ( pml.groundPlane )
        {
            if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
            {   // slide along the ground plane
                PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
                                 pm->ps->velocity, OVERCLIP );
            }
        }
    }

    time_left = pml.frametime;

    // never turn against the ground plane
    if ( pml.groundPlane )
    {
        numplanes = 1;
        VectorCopy( pml.groundTrace.plane.normal, planes[0] );
        if ( !PM_GroundSlideOkay( planes[0][2] ) )
        {
            planes[0][2] = 0;
            VectorNormalize( planes[0] );
        }
    }
    else
    {
        numplanes = 0;
    }

    // never turn against original velocity
    VectorNormalize2( pm->ps->velocity, planes[numplanes] );
    numplanes++;

    for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {

        // calculate position we are trying to move to
        VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

        // see if we can make it there
        pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, slideMoveContents, (EG2_Collision)0, 0 );
        if ( (trace.contents&CONTENTS_BOTCLIP)
                && (slideMoveContents&CONTENTS_BOTCLIP) )
        {   //hit a do not enter brush
            if ( trace.allsolid || trace.startsolid  )//inside the botclip
            {   //crap, we're in a do not enter brush, take it out for the remainder of the traces and re-trace this one right now without it
                slideMoveContents &= ~CONTENTS_BOTCLIP;
                pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, slideMoveContents, (EG2_Collision)0, 0 );
            }
            else if ( trace.plane.normal[2] > 0.0f )
            {   //on top of a do not enter brush, it, just redo this one trace without it
                pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, (slideMoveContents&~CONTENTS_BOTCLIP), (EG2_Collision)0, 0 );
            }
        }

        if ( trace.allsolid )
        {   // entity is completely trapped in another solid
            pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
            return qtrue;
        }

        if ( trace.fraction > 0 )
        {   // actually covered some distance
            VectorCopy( trace.endpos, pm->ps->origin );
        }

        if ( trace.fraction == 1 )
        {
            break;		// moved the entire distance
        }



        // save entity for contact
        PM_AddTouchEnt( trace.entityNum );

        //Hit it
        if ( trace.surfaceFlags&SURF_NODAMAGE )
        {
            damageSelf = qfalse;
        }
        else if ( trace.entityNum == ENTITYNUM_WORLD && trace.plane.normal[2] > 0.5f )
        {   //if we land on the ground, let falling damage do it's thing itself, otherwise do impact damage
            damageSelf = qfalse;
        }
        else
        {
            damageSelf = qtrue;
        }

        if ( PM_ClientImpact( &trace, damageSelf ) )
        {
            continue;
        }

        if (pm->gent->client &&
                pm->gent->client->NPC_class == CLASS_VEHICLE &&
                trace.plane.normal[2]<pm->gent->m_pVehicle->m_pVehicleInfo->maxSlope
           )
        {
            pm->ps->pm_flags |= PMF_BUMPED;
        }

        time_left -= time_left * trace.fraction;

        if ( numplanes >= MAX_CLIP_PLANES )
        {   // this shouldn't really happen
            VectorClear( pm->ps->velocity );
            return qtrue;
        }

        VectorCopy( trace.plane.normal, normal );

        if ( !PM_GroundSlideOkay( normal[2] ) )
        {   //wall-running
            //never push up off a sloped wall
            normal[2] = 0;
            VectorNormalize( normal );
        }

        //
        // if this is the same plane we hit before, nudge velocity
        // out along it, which fixes some epsilon issues with
        // non-axial planes
        //
        if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
        {   //no sliding if stuck to wall!
            for ( i = 0 ; i < numplanes ; i++ ) {
                if ( DotProduct( normal, planes[i] ) > 0.99 ) {
                    VectorAdd( normal, pm->ps->velocity, pm->ps->velocity );
                    break;
                }
            }
            if ( i < numplanes ) {
                continue;
            }
        }
        VectorCopy( normal, planes[numplanes] );
        numplanes++;

        //
        // modify velocity so it parallels all of the clip planes
        //

        // find a plane that it enters
        for ( i = 0 ; i < numplanes ; i++ ) {
            into = DotProduct( pm->ps->velocity, planes[i] );
            if ( into >= 0.1 ) {
                continue;		// move doesn't interact with the plane
            }

            // see how hard we are hitting things
            if ( -into > pml.impactSpeed ) {
                pml.impactSpeed = -into;
            }

            // slide along the plane
            PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

            // slide along the plane
            PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

            // see if there is a second plane that the new move enters
            for ( j = 0 ; j < numplanes ; j++ ) {
                if ( j == i ) {
                    continue;
                }
                if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
                    continue;		// move doesn't interact with the plane
                }

                // try clipping the move to the plane
                PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
                PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

                // see if it goes back into the first clip plane
                if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
                    continue;
                }

                // slide the original velocity along the crease
                CrossProduct (planes[i], planes[j], dir);
                VectorNormalize( dir );
                d = DotProduct( dir, pm->ps->velocity );
                VectorScale( dir, d, clipVelocity );

                CrossProduct (planes[i], planes[j], dir);
                VectorNormalize( dir );
                d = DotProduct( dir, endVelocity );
                VectorScale( dir, d, endClipVelocity );

                // see if there is a third plane the the new move enters
                for ( k = 0 ; k < numplanes ; k++ ) {
                    if ( k == i || k == j ) {
                        continue;
                    }
                    if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
                        continue;		// move doesn't interact with the plane
                    }

                    // stop dead at a triple plane interaction
                    VectorClear( pm->ps->velocity );
                    return qtrue;
                }
            }

            // if we have fixed all interactions, try another move
            VectorCopy( clipVelocity, pm->ps->velocity );
            VectorCopy( endClipVelocity, endVelocity );
            break;
        }
    }

    if ( gravMod ) {
        VectorCopy( endVelocity, pm->ps->velocity );
    }

    // don't change velocity if in a timer (FIXME: is this correct?)
    if ( pm->ps->pm_time ) {
        VectorCopy( primal_velocity, pm->ps->velocity );
    }

    return ( bumpcount != 0 );
}
Esempio n. 9
0
/**
 * @brief Update the camera position. This can be done in two different reasons. The first is the user input, the second
 * is an active camera route. The camera route overrides the user input and is lerping the movement until the final position
 * is reached.
 */
void CL_CameraMove (void)
{
	float frac;
	vec3_t delta;
	int i;

	/* get relevant variables */
	const float rotspeed =
		(cl_camrotspeed->value > MIN_CAMROT_SPEED) ? ((cl_camrotspeed->value < MAX_CAMROT_SPEED) ? cl_camrotspeed->value : MAX_CAMROT_SPEED) : MIN_CAMROT_SPEED;
	const float movespeed =
		(cl_cammovespeed->value > MIN_CAMMOVE_SPEED) ?
		((cl_cammovespeed->value < MAX_CAMMOVE_SPEED) ? cl_cammovespeed->value / cl.cam.zoom : MAX_CAMMOVE_SPEED / cl.cam.zoom) : MIN_CAMMOVE_SPEED / cl.cam.zoom;
	const float moveaccel =
		(cl_cammoveaccel->value > MIN_CAMMOVE_ACCEL) ?
		((cl_cammoveaccel->value < MAX_CAMMOVE_ACCEL) ? cl_cammoveaccel->value / cl.cam.zoom : MAX_CAMMOVE_ACCEL / cl.cam.zoom) : MIN_CAMMOVE_ACCEL / cl.cam.zoom;

	if (cls.state != ca_active)
		return;

	if (!viddef.viewWidth || !viddef.viewHeight)
		return;

	/* calculate camera omega */
	/* stop acceleration */
	frac = cls.frametime * moveaccel * 2.5;

	for (i = 0; i < 2; i++) {
		if (fabs(cl.cam.omega[i]) > frac) {
			if (cl.cam.omega[i] > 0)
				cl.cam.omega[i] -= frac;
			else
				cl.cam.omega[i] += frac;
		} else
			cl.cam.omega[i] = 0;

		/* rotational acceleration */
		if (i == YAW)
			cl.cam.omega[i] += CL_GetKeyMouseState(STATE_ROT) * frac * 2;
		else
			cl.cam.omega[i] += CL_GetKeyMouseState(STATE_TILT) * frac * 2;

		if (cl.cam.omega[i] > rotspeed)
			cl.cam.omega[i] = rotspeed;
		if (-cl.cam.omega[i] > rotspeed)
			cl.cam.omega[i] = -rotspeed;
	}

	cl.cam.omega[ROLL] = 0;
	/* calculate new camera angles for this frame */
	VectorMA(cl.cam.angles, cls.frametime, cl.cam.omega, cl.cam.angles);

	if (cl.cam.angles[PITCH] > cl_campitchmax->value)
		cl.cam.angles[PITCH] = cl_campitchmax->value;
	if (cl.cam.angles[PITCH] < cl_campitchmin->value)
		cl.cam.angles[PITCH] = cl_campitchmin->value;

	AngleVectors(cl.cam.angles, cl.cam.axis[0], cl.cam.axis[1], cl.cam.axis[2]);

	/* camera route overrides user input */
	if (cameraRoute) {
		/* camera route */
		frac = cls.frametime * moveaccel * 2;
		if (VectorDist(cl.cam.origin, routeFrom) > routeDist - 200) {
			VectorMA(cl.cam.speed, -frac, routeDelta, cl.cam.speed);
			VectorNormalize2(cl.cam.speed, delta);
			if (DotProduct(delta, routeDelta) < 0.05) {
				cameraRoute = false;

				CL_BlockBattlescapeEvents(false);
			}
		} else
			VectorMA(cl.cam.speed, frac, routeDelta, cl.cam.speed);
	} else {
		/* normal camera movement */
		/* calculate ground-based movement vectors */
		const float angle = cl.cam.angles[YAW] * torad;
		const float sy = sin(angle);
		const float cy = cos(angle);
		vec3_t g_forward, g_right;

		VectorSet(g_forward, cy, sy, 0.0);
		VectorSet(g_right, sy, -cy, 0.0);

		/* calculate camera speed */
		/* stop acceleration */
		frac = cls.frametime * moveaccel;
		if (VectorLength(cl.cam.speed) > frac) {
			VectorNormalize2(cl.cam.speed, delta);
			VectorMA(cl.cam.speed, -frac, delta, cl.cam.speed);
		} else
			VectorClear(cl.cam.speed);

		/* acceleration */
		frac = cls.frametime * moveaccel * 3.5;
		VectorClear(delta);
		VectorScale(g_forward, CL_GetKeyMouseState(STATE_FORWARD), delta);
		VectorMA(delta, CL_GetKeyMouseState(STATE_RIGHT), g_right, delta);
		VectorNormalize(delta);
		VectorMA(cl.cam.speed, frac, delta, cl.cam.speed);

		/* lerp the level change */
		if (cl.cam.lerplevel < cl_worldlevel->value) {
			cl.cam.lerplevel += LEVEL_SPEED * (cl_worldlevel->value - cl.cam.lerplevel + LEVEL_MIN) * cls.frametime;
			if (cl.cam.lerplevel > cl_worldlevel->value)
				cl.cam.lerplevel = cl_worldlevel->value;
		} else if (cl.cam.lerplevel > cl_worldlevel->value) {
			cl.cam.lerplevel -= LEVEL_SPEED * (cl.cam.lerplevel - cl_worldlevel->value + LEVEL_MIN) * cls.frametime;
			if (cl.cam.lerplevel < cl_worldlevel->value)
				cl.cam.lerplevel = cl_worldlevel->value;
		}
	}

	/* clamp speed */
	frac = VectorLength(cl.cam.speed) / movespeed;
	if (frac > 1.0)
		VectorScale(cl.cam.speed, 1.0 / frac, cl.cam.speed);

	/* zoom change */
	frac = CL_GetKeyMouseState(STATE_ZOOM);
	if (frac > 0.1) {
		cl.cam.zoom *= 1.0 + cls.frametime * cl_camzoomspeed->value * frac;
		/* ensure zoom isn't greater than either MAX_ZOOM or cl_camzoommax */
		cl.cam.zoom = std::min(std::min(MAX_ZOOM, cl_camzoommax->value), cl.cam.zoom);
	} else if (frac < -0.1) {
		cl.cam.zoom /= 1.0 - cls.frametime * cl_camzoomspeed->value * frac;
		/* ensure zoom isn't less than either MIN_ZOOM or cl_camzoommin */
		cl.cam.zoom = std::max(std::max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
	}
	CL_ViewCalcFieldOfViewX();

	/* calc new camera reference and new camera real origin */
	VectorMA(cl.cam.origin, cls.frametime, cl.cam.speed, cl.cam.origin);
	cl.cam.origin[2] = 0.;
	if (cl_isometric->integer) {
		CL_ClampCamToMap(72.);
		VectorMA(cl.cam.origin, -CAMERA_START_DIST + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT, cl.cam.axis[0], cl.cam.camorg);
		cl.cam.camorg[2] += CAMERA_START_HEIGHT + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT;
	} else {
		const double border = 144.0 * (cl.cam.zoom - cl_camzoommin->value - 0.4) / cl_camzoommax->value;
		CL_ClampCamToMap(std::min(border, 86.0));
		VectorMA(cl.cam.origin, -CAMERA_START_DIST / cl.cam.zoom , cl.cam.axis[0], cl.cam.camorg);
		cl.cam.camorg[2] += CAMERA_START_HEIGHT / cl.cam.zoom + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT;
	}
}
Esempio n. 10
0
/*
================
CM_TraceThroughVerticalCylinder

get the first intersection of the ray with the cylinder
the cylinder extends halfheight above and below the origin
================
*/
void CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end, int contents) {
	float length, fraction, l1, l2;
	//float a;
	float b, c, d, sqrtd;
	vec3_t v1, dir, start2d, end2d, org2d, intersection;

	// 2d coordinates
	VectorSet(start2d, start[0], start[1], 0);
	VectorSet(end2d, end[0], end[1], 0);
	VectorSet(org2d, origin[0], origin[1], 0);
	// if start is between lower and upper cylinder bounds
	if (start[2] <= origin[2] + halfheight &&
				start[2] >= origin[2] - halfheight) {
		// if inside the cylinder
		VectorSubtract(start2d, org2d, dir);
		l1 = VectorLengthSquared(dir);
		if (l1 < Square(radius)) {
			tw->trace.startsolid = qtrue;

			// if end is between lower and upper cylinder bounds
			if (end[2] <= origin[2] + halfheight &&
						end[2] >= origin[2] - halfheight) {
				// test for allsolid
				VectorSubtract(end2d, org2d, dir);
				l1 = VectorLengthSquared(dir);
				if (l1 < Square(radius)) {
					tw->trace.allsolid = qtrue;
					tw->trace.fraction = 0;
					tw->trace.contents = contents;
				}
			}
			return;
		}
	}
	//
	VectorSubtract(end2d, start2d, dir);
	length = VectorNormalize(dir);
	//
	l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
	VectorSubtract(end2d, org2d, v1);
	l2 = VectorLengthSquared(v1);
	// if no intersection with the cylinder and the end point is at least an epsilon away
	if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
		return;
	}
	//
	//
	// (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
	// (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
	// v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
	//						v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
	// t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
	//						v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
	//
	VectorSubtract(start, origin, v1);
	// dir is normalized so we can use a = 1
	//a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
	b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
	c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);

	d = b * b - 4.0f * c;// * a;
	if (d > 0) {
		sqrtd = SquareRootFloat(d);
		// = (- b + sqrtd) * 0.5f;// / (2.0f * a);
		fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
		//
		if (fraction < 0) {
			fraction = 0;
		}
		else {
			fraction /= length;
		}
		if ( fraction < tw->trace.fraction ) {
			VectorSubtract(end, start, dir);
			VectorMA(start, fraction, dir, intersection);
			// if the intersection is between the cylinder lower and upper bound
			if (intersection[2] <= origin[2] + halfheight &&
						intersection[2] >= origin[2] - halfheight) {
				//
				tw->trace.fraction = fraction;
				VectorSubtract(intersection, origin, dir);
				dir[2] = 0;
				#ifdef CAPSULE_DEBUG
					l2 = VectorLength(dir);
					if (l2 <= radius) {
						int bah = 1;
					}
				#endif
#if 1 // ZTM: NOTE: Old method caused CM_Trace to fail assert at bottom of CM_Trace sometimes.
				VectorNormalize2(dir, tw->trace.plane.normal);
#else
				{
					float scale;
					scale = 1 / (radius+RADIUS_EPSILON);
					VectorScale(dir, scale, dir);
					VectorCopy(dir, tw->trace.plane.normal);
				}
#endif
				VectorAdd( tw->modelOrigin, intersection, intersection);
				tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
				tw->trace.contents = contents;
			}
		}
	}
	else if (d == 0) {
		//t[0] = (- b ) / 2 * a;
		// slide along the cylinder
	}
	// no intersection at all
}
Esempio n. 11
0
/*
================
CM_TraceThroughLeaf
================
*/
void CM_TraceThroughLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
	int			k;
	int			brushnum;
	int			surfnum;
	cbrush_t	*b;
	cPatch_t	*patch;

	// trace line against all brushes in the leaf
	for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
		brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];

		b = &cm.brushes[brushnum];
		if ( b->checkcount == cm.checkcount ) {
			continue;	// already checked this brush in another leaf
		}
		b->checkcount = cm.checkcount;

		if ( !(b->contents & tw->contents) ) {
			continue;
		}

		b->collided = qfalse;

		if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1],
					b->bounds[0], b->bounds[1] ) ) {
			continue;
		}

		CM_TraceThroughBrush( tw, b );
		if ( !tw->trace.fraction ) {
			tw->trace.lateralFraction = 0.0f;
			return;
		}
	}

	// trace line against all patches in the leaf
#ifdef BSPC
	if (1) {
#else
	if ( !cm_noCurves->integer ) {
#endif
		for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
			surfnum = cm.leafsurfaces[ leaf->firstLeafSurface + k ];
			patch = cm.surfaces[ surfnum ];
			if ( !patch ) {
				continue;
			}
			if ( patch->checkcount == cm.checkcount ) {
				continue;	// already checked this patch in another leaf
			}
			patch->checkcount = cm.checkcount;

			if ( !(patch->contents & tw->contents) ) {
				continue;
			}
			
			CM_TraceThroughPatch( tw, patch, surfnum );

			if ( !tw->trace.fraction ) {
				tw->trace.lateralFraction = 0.0f;
				return;
			}
		}
	}

	if( tw->testLateralCollision && tw->trace.fraction < 1.0f )
	{
		for( k = 0; k < leaf->numLeafBrushes; k++ )
		{
			brushnum = cm.leafbrushes[ leaf->firstLeafBrush + k ];

			b = &cm.brushes[ brushnum ];

			// This brush never collided, so don't bother
			if( !b->collided )
				continue;

			if( !( b->contents & tw->contents ) )
				continue;

			CM_ProximityToBrush( tw, b );

			if( !tw->trace.lateralFraction )
				return;
		}

		for( k = 0; k < leaf->numLeafSurfaces; k++ )
		{
			surfnum = cm.leafsurfaces[ leaf->firstLeafSurface + k ];
			patch = cm.surfaces[ surfnum ];
			if( !patch )
				continue;

			if( !( patch->contents & tw->contents ) )
				continue;
			
			CM_ProximityToPatch( tw, patch, surfnum );

			if( !tw->trace.lateralFraction )
				return;
		}
	}
}

#define RADIUS_EPSILON		1.0f

/*
================
CM_TraceThroughSphere

get the first intersection of the ray with the sphere
================
*/
void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end, int contents ) {
	float l1, l2, length, fraction;
	//float a;
	float b, c, d, sqrtd;
	vec3_t v1, dir, intersection;

	// if inside the sphere
	VectorSubtract(start, origin, dir);
	l1 = VectorLengthSquared(dir);
	if (l1 < Square(radius)) {
		tw->trace.startsolid = qtrue;

		// test for allsolid
		VectorSubtract(end, origin, dir);
		l1 = VectorLengthSquared(dir);
		if (l1 < Square(radius)) {
			tw->trace.allsolid = qtrue;
			tw->trace.fraction = 0;
			tw->trace.contents = contents;
		}
		return;
	}
	//
	VectorSubtract(end, start, dir);
	length = VectorNormalize(dir);
	//
	l1 = CM_DistanceFromLineSquared(origin, start, end, dir);
	VectorSubtract(end, origin, v1);
	l2 = VectorLengthSquared(v1);
	// if no intersection with the sphere and the end point is at least an epsilon away
	if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
		return;
	}
	//
	//	| origin - (start + t * dir) | = radius
	//	a = dir[0]^2 + dir[1]^2 + dir[2]^2;
	//	b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
	//	c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
	//
	VectorSubtract(start, origin, v1);
	// dir is normalized so a = 1
	//a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
	b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);
	c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);

	d = b * b - 4.0f * c;// * a;
	if (d > 0) {
		sqrtd = SquareRootFloat(d);
		// = (- b + sqrtd) * 0.5f; // / (2.0f * a);
		fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);
		//
		if (fraction < 0) {
			fraction = 0;
		}
		else {
			fraction /= length;
		}
		if ( fraction < tw->trace.fraction ) {
			tw->trace.fraction = fraction;
			VectorSubtract(end, start, dir);
			VectorMA(start, fraction, dir, intersection);
			VectorSubtract(intersection, origin, dir);
			#ifdef CAPSULE_DEBUG
				l2 = VectorLength(dir);
				if (l2 < radius) {
					int bah = 1;
				}
			#endif
#if 1 // ZTM: NOTE: Old method caused CM_Trace to fail assert at bottom of CM_Trace sometimes.
			VectorNormalize2(dir, tw->trace.plane.normal);
#else
			{
				float scale;
				scale = 1 / (radius+RADIUS_EPSILON);
				VectorScale(dir, scale, dir);
				VectorCopy(dir, tw->trace.plane.normal);
			}
#endif
			VectorAdd( tw->modelOrigin, intersection, intersection);
			tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
			tw->trace.contents = contents;
		}
	}
	else if (d == 0) {
		//t1 = (- b ) / 2;
		// slide along the sphere
	}
	// no intersection at all
}
Esempio n. 12
0
/*
=================
R_SetupEntityLightingGrid

=================
*/
static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
	vec3_t	lightOrigin;
	//int		pos[3];

	//byte	*gridData;
	//float	frac[3];
	//int		gridStep[3];
	vec3_t	direction;
	//float	totalFactor;

	int		i, j;
	int		k, s;
	int		vi[3], elem[4];
	float	t[8];
	vec3_t	vf, vf2, tdir;
	vec_t	*gridSize, *gridMins;
	int		*gridBounds;
	static dgrid_t lightarray[8];

	if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
		// seperate lightOrigins are needed so an object that is
		// sinking into the ground can still be lit, and so
		// multi-part models can be lit identically
		VectorCopy( ent->e.lightingOrigin, lightOrigin );
	} else {
		VectorCopy( ent->e.origin, lightOrigin );
	}

	gridSize = tr.world->lightGridSize;
	gridMins = tr.world->lightGridMins;
	gridBounds = tr.world->lightGridBounds;

	for( i = 0; i < 3; i++ )
	{
		vf[i] = ( lightOrigin[i] - gridMins[i] ) / gridSize[i];
		vi[i] = (int)vf[i];
		vf[i] = vf[i] - floor( vf[i] );
		vf2[i] = 1.0f - vf[i];
	}

	elem[0] = vi[2] * gridBounds[3] + vi[1] * gridBounds[0] + vi[0];
	elem[1] = elem[0] + gridBounds[0];
	elem[2] = elem[0] + gridBounds[3];
	elem[3] = elem[2] + gridBounds[0];

	for( i = 0; i < 4; i++ )
	{
		lightarray[i*2+0] = *tr.world->lightGridArray[BOUND( 0, elem[i]+0, tr.world->numLightGridArrayItems-1)];
		lightarray[i*2+1] = *tr.world->lightGridArray[BOUND( 0, elem[i]+1, tr.world->numLightGridArrayItems-1)];
	}

	t[0] = vf2[0] * vf2[1] * vf2[2];
	t[1] = vf[0] * vf2[1] * vf2[2];
	t[2] = vf2[0] * vf[1] * vf2[2];
	t[3] = vf[0] * vf[1] * vf2[2];
	t[4] = vf2[0] * vf2[1] * vf[2];
	t[5] = vf[0] * vf2[1] * vf[2];
	t[6] = vf2[0] * vf[1] * vf[2];
	t[7] = vf[0] * vf[1] * vf[2];

	VectorClear( ent->ambientLight );
	VectorClear( ent->directedLight );
	VectorClear( direction );

	for( i = 0; i < 4; i++ )
	{
		R_LatLongToNorm( lightarray[i*2].latLong, tdir );
		VectorScale( tdir, t[i*2], tdir );
		for( k = 0; k < MAXLIGHTMAPS && ( s = lightarray[i*2].styles[k] ) != 255; k++ )
		{
			direction[0] += tr.lightStyles[s].rgb[0] * tdir[0];
			direction[1] += tr.lightStyles[s].rgb[1] * tdir[1];
			direction[2] += tr.lightStyles[s].rgb[2] * tdir[2];
		}

		R_LatLongToNorm( lightarray[i*2+1].latLong, tdir );
		VectorScale( tdir, t[i*2+1], tdir );
		for( k = 0; k < MAXLIGHTMAPS && ( s = lightarray[i*2+1].styles[k] ) != 255; k++ )
		{
			direction[0] += tr.lightStyles[s].rgb[0] * tdir[0];
			direction[1] += tr.lightStyles[s].rgb[1] * tdir[1];
			direction[2] += tr.lightStyles[s].rgb[2] * tdir[2];
		}
	}

	for( j = 0; j < 3; j++ )
	{
		//if( ambient )
		{
			for( i = 0; i < 4; i++ )
			{
				for( k = 0; k < MAXLIGHTMAPS; k++ )
				{
					if( ( s = lightarray[i*2].styles[k] ) != 255 )
						ent->ambientLight[j] += t[i*2] * lightarray[i*2].ambientLight[k][j] * tr.lightStyles[s].rgb[j];
					if( ( s = lightarray[i*2+1].styles[k] ) != 255 )
						ent->ambientLight[j] += t[i*2+1] * lightarray[i*2+1].ambientLight[k][j] * tr.lightStyles[s].rgb[j];
				}
			}
		}
		//if( diffuse || radius )
		{
			for( i = 0; i < 4; i++ )
			{
				for( k = 0; k < MAXLIGHTMAPS; k++ )
				{
					if( ( s = lightarray[i*2].styles[k] ) != 255 )
						ent->directedLight[j] += t[i*2] * lightarray[i*2].directLight[k][j] * tr.lightStyles[s].rgb[j];
					if( ( s = lightarray[i*2+1].styles[k] ) != 255 )
						ent->directedLight[j] += t[i*2+1] * lightarray[i*2+1].directLight[k][j] * tr.lightStyles[s].rgb[j];
				}
			}
		}
	}

	VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
	VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );

	VectorNormalize2( direction, ent->lightDir );

#if 0

	//VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );

	for ( i = 0 ; i < 3 ; i++ ) {
		float	v;

		v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
		pos[i] = floor( v );
		frac[i] = v - pos[i];
		if ( pos[i] < 0 ) {
			pos[i] = 0;
		} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
			pos[i] = tr.world->lightGridBounds[i] - 1;
		}
	}

	VectorClear( ent->ambientLight );
	VectorClear( ent->directedLight );
	VectorClear( direction );

	assert( tr.world->lightGridData ); // NULL with -nolight maps

	// trilerp the light value
	gridStep[0] = 8;
	gridStep[1] = 8 * tr.world->lightGridBounds[0];
	gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
	gridData = tr.world->lightGridData + pos[0] * gridStep[0]
		+ pos[1] * gridStep[1] + pos[2] * gridStep[2];

	totalFactor = 0;
	for ( i = 0 ; i < 8 ; i++ ) {
		float	factor;
		byte	*data;
		int		lat, lng;
		vec3_t	normal;
		#if idppc
		float d0, d1, d2, d3, d4, d5;
		#endif
		factor = 1.0;
		data = gridData;
		for ( j = 0 ; j < 3 ; j++ ) {
			if ( i & (1<<j) ) {
				factor *= frac[j];
				data += gridStep[j];
			} else {
				factor *= (1.0f - frac[j]);
			}
		}

		if ( !(data[0]+data[1]+data[2]) ) {
			continue;	// ignore samples in walls
		}
		totalFactor += factor;
		#if idppc
		d0 = data[0]; d1 = data[1]; d2 = data[2];
		d3 = data[3]; d4 = data[4]; d5 = data[5];

		ent->ambientLight[0] += factor * d0;
		ent->ambientLight[1] += factor * d1;
		ent->ambientLight[2] += factor * d2;

		ent->directedLight[0] += factor * d3;
		ent->directedLight[1] += factor * d4;
		ent->directedLight[2] += factor * d5;
		#else
		ent->ambientLight[0] += factor * data[0];
		ent->ambientLight[1] += factor * data[1];
		ent->ambientLight[2] += factor * data[2];

		ent->directedLight[0] += factor * data[3];
		ent->directedLight[1] += factor * data[4];
		ent->directedLight[2] += factor * data[5];
		#endif
		lat = data[7];
		lng = data[6];
		lat *= (FUNCTABLE_SIZE/256);
		lng *= (FUNCTABLE_SIZE/256);

		// decode X as cos( lat ) * sin( long )
		// decode Y as sin( lat ) * sin( long )
		// decode Z as cos( long )

		normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
		normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
		normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];

		VectorMA( direction, factor, normal, direction );
	}

	if ( totalFactor > 0 && totalFactor < 0.99 ) {
		totalFactor = 1.0f / totalFactor;
		VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
		VectorScale( ent->directedLight, totalFactor, ent->directedLight );
	}

	VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
	VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );

	VectorNormalize2( direction, ent->lightDir );
#endif
}
Esempio n. 13
0
//FIXME since we need to test end position contents here, can we avoid doing
//it again later in catagorize position?
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
{
	float		dz;
	vec3_t		oldorg, neworg, end;
	trace_t		trace;
	int			i;
	float		stepsize;
	float		jumpheight;
	vec3_t		test;
	int			contents;

	qboolean	canjump;
	float		d1, d2;
	int			jump;		// 1=jump up, -1=jump down
	vec3_t		forward, up;
	vec3_t		dir;
	vec_t		dist;
	vec_t		g1, g2;
	edict_t		*grenade;
	edict_t		*target;

	// try the move	
	VectorCopy (ent->s.origin, oldorg);
	VectorAdd (ent->s.origin, move, neworg);

	AngleVectors(ent->s.angles,forward,NULL,up);
	if(ent->enemy)
		target = ent->enemy;
	else if(ent->movetarget)
		target = ent->movetarget;
	else
		target = NULL;

	// flying monsters don't step up
	if ( ent->flags & (FL_SWIM | FL_FLY) )
	{
		// try one move with vertical motion, then one without
		for (i=0 ; i<2 ; i++)
		{
			VectorAdd (ent->s.origin, move, neworg);
			if (i == 0 && ent->enemy)
			{
				if (!ent->goalentity)
					ent->goalentity = ent->enemy;
				dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
				if (ent->goalentity->client)
				{
					if (dz > 40)
						neworg[2] -= 8;
					if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
						if (dz < 30)
							neworg[2] += 8;
				}
				else
				{
					if (dz > 8)
						neworg[2] -= 8;
					else if (dz > 0)
						neworg[2] -= dz;
					else if (dz < -8)
						neworg[2] += 8;
					else
						neworg[2] += dz;
				}
			}
			trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
	
			// fly monsters don't enter water voluntarily
			if (ent->flags & FL_FLY)
			{
				if (!ent->waterlevel)
				{
					test[0] = trace.endpos[0];
					test[1] = trace.endpos[1];
					test[2] = trace.endpos[2] + ent->mins[2] + 1;
					contents = gi.pointcontents(test);
					if (contents & MASK_WATER)
						return false;
				}
			}

			// swim monsters don't exit water voluntarily
			if (ent->flags & FL_SWIM)
			{
				if (ent->waterlevel < 2)
				{
					test[0] = trace.endpos[0];
					test[1] = trace.endpos[1];
					test[2] = trace.endpos[2] + ent->mins[2] + 1;
					contents = gi.pointcontents(test);
					if (!(contents & MASK_WATER))
						return false;
				}
			}

			if (trace.fraction == 1)
			{
				VectorCopy (trace.endpos, ent->s.origin);
				if (relink)
				{
					gi.linkentity (ent);
					G_TouchTriggers (ent);
				}
				return true;
			}
			
			if (!ent->enemy)
				break;
		}
		
		return false;
	}

	// push down from a step height above the wished position
	if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
		stepsize = STEPSIZE;
	else
		stepsize = 1;

	neworg[2] += stepsize;
	VectorCopy (neworg, end);
	end[2] -= stepsize*2;

	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);

	// Determine whether monster is capable of and/or should jump
	jump = 0;
	if((ent->monsterinfo.jump) && !(ent->monsterinfo.aiflags & AI_DUCKED))
	{
		// Don't jump if path is blocked by monster or player. Otherwise,
		// monster might attempt to jump OVER the monster/player, which 
		// ends up looking a bit goofy. Also don't jump if the monster's
		// movement isn't deliberate (target=NULL)
		if(trace.ent && (trace.ent->client || (trace.ent->svflags & SVF_MONSTER)))
			canjump = false;
		else if(target)
		{
			// Never jump unless it places monster closer to his goal
			vec3_t	dir;
			VectorSubtract(target->s.origin, oldorg, dir);
			d1 = VectorLength(dir);
			VectorSubtract(target->s.origin, trace.endpos, dir);
			d2 = VectorLength(dir);
			if(d2 < d1)
				canjump = true;
			else
				canjump = false;
		}
		else
			canjump = false;
	}
	else
		canjump = false;

	if (trace.allsolid)
	{
		if(canjump && (ent->monsterinfo.jumpup > 0))
		{
			neworg[2] += ent->monsterinfo.jumpup - stepsize;
			trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
			if (!trace.allsolid && !trace.startsolid && trace.fraction > 0 && (trace.plane.normal[2] > 0.9))
			{
				if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER)))
				{
					// Good plane to jump on. Make sure monster is more or less facing
					// the obstacle to avoid cutting-corners jumps
					trace_t	tr;
					vec3_t	p2;

					VectorMA(ent->s.origin,1024,forward,p2);
					tr = gi.trace(ent->s.origin,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID);
					if(DotProduct(tr.plane.normal,forward) < -0.95)
					{
						jump = 1;
						jumpheight = trace.endpos[2] - ent->s.origin[2];
					}
					else
						return false;
				}
			}
			else
				return false;
		}
		else
			return false;
	}

	if (trace.startsolid)
	{
		neworg[2] -= stepsize;
		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
		if (trace.allsolid || trace.startsolid)
			return false;
	}


	// don't go in to water
	// Lazarus: misc_actors don't go swimming, but wading is fine
	if (ent->monsterinfo.aiflags & AI_ACTOR)
	{
		// First check for lava/slime under feet - but only if we're not already in
		// a liquid
		test[0] = trace.endpos[0];
		test[1] = trace.endpos[1];
		if (ent->waterlevel == 0)
		{
			test[2] = trace.endpos[2] + ent->mins[2] + 1;	
			contents = gi.pointcontents(test);
			if (contents & (CONTENTS_LAVA | CONTENTS_SLIME))
				return false;
		}
		test[2] = trace.endpos[2] + ent->viewheight - 1;
		contents = gi.pointcontents(test);
		if (contents & MASK_WATER)
			return false;
	}
	else if (ent->waterlevel == 0)
	{
		test[0] = trace.endpos[0];
		test[1] = trace.endpos[1];
		test[2] = trace.endpos[2] + ent->mins[2] + 1;	
		contents = gi.pointcontents(test);

		if (contents & MASK_WATER)
			return false;
	}

	// Lazarus: Don't intentionally move closer to a grenade,
	//          but don't perform this check if we're already evading some
	//          other problem (maybe even this grenade)
	if(!(ent->monsterinfo.aiflags & AI_CHASE_THING))
	{
		grenade = NULL;
		while( (grenade=findradius(grenade,neworg,128)) != NULL)
		{
			if(!grenade->inuse)
				continue;
			if(!grenade->classname)
				continue;
			if(!Q_stricmp(grenade->classname,"grenade") || !Q_stricmp(grenade->classname,"hgrenade"))
			{
				VectorSubtract(grenade->s.origin,oldorg,dir);
				g1 = VectorLength(dir);
				VectorSubtract(grenade->s.origin,neworg,dir);
				g2 = VectorLength(dir);
				if(g2 < g1)
					return false;
			}
		}
	}
	// Lazarus: Don't intentionally walk into lasers.
	dist = VectorLength(move);
	if(dist > 0.)
	{
		edict_t		*e;
		trace_t		laser_trace;
		vec_t		delta;
		vec3_t		laser_mins, laser_maxs;
		vec3_t		laser_start, laser_end;
		vec3_t		monster_mins, monster_maxs;

		for(i=game.maxclients+1; i<globals.num_edicts; i++)
		{
			e = &g_edicts[i];
			if(!e->inuse)
				continue;
			if(!e->classname)
				continue;
			if(Q_stricmp(e->classname,"target_laser"))
				continue;
			if(e->svflags & SVF_NOCLIENT)
				continue;
			if( (e->style == 2) || (e->style == 3))
				continue;
			if(!gi.inPVS(ent->s.origin,e->s.origin))
				continue;
			// Check to see if monster is ALREADY in the path of this laser.
			// If so, allow the move so he can get out.
			VectorMA(e->s.origin,2048,e->movedir,laser_end);
			laser_trace = gi.trace(e->s.origin,NULL,NULL,laser_end,NULL,CONTENTS_SOLID|CONTENTS_MONSTER);
			if(laser_trace.ent == ent)
				continue;
			VectorCopy(laser_trace.endpos,laser_end);
			laser_mins[0] = min(e->s.origin[0],laser_end[0]);
			laser_mins[1] = min(e->s.origin[1],laser_end[1]);
			laser_mins[2] = min(e->s.origin[2],laser_end[2]);
			laser_maxs[0] = max(e->s.origin[0],laser_end[0]);
			laser_maxs[1] = max(e->s.origin[1],laser_end[1]);
			laser_maxs[2] = max(e->s.origin[2],laser_end[2]);
			monster_mins[0] = min(oldorg[0],trace.endpos[0]) + ent->mins[0];
			monster_mins[1] = min(oldorg[1],trace.endpos[1]) + ent->mins[1];
			monster_mins[2] = min(oldorg[2],trace.endpos[2]) + ent->mins[2];
			monster_maxs[0] = max(oldorg[0],trace.endpos[0]) + ent->maxs[0];
			monster_maxs[1] = max(oldorg[1],trace.endpos[1]) + ent->maxs[1];
			monster_maxs[2] = max(oldorg[2],trace.endpos[2]) + ent->maxs[2];
			if( monster_maxs[0] < laser_mins[0] ) continue;
			if( monster_maxs[1] < laser_mins[1] ) continue;
			if( monster_maxs[2] < laser_mins[2] ) continue;
			if( monster_mins[0] > laser_maxs[0] ) continue;
			if( monster_mins[1] > laser_maxs[1] ) continue;
			if( monster_mins[2] > laser_maxs[2] ) continue;
			// If we arrive here, some part of the bounding box surrounding
			// monster's total movement intersects laser bounding box.
			// If laser is parallel to x, y, or z, we definitely
			// know this move will put monster in path of laser
			if ( (e->movedir[0] == 1.) || (e->movedir[1] == 1.) || (e->movedir[2] == 1.))
				return false;
			// Shift psuedo laser towards monster's current position up to
			// the total distance he's proposing moving.
			delta = min(16,dist);
			VectorNormalize2(move,dir);
			while(delta < dist+15.875)
			{
				if(delta > dist) delta = dist;
				VectorMA(e->s.origin,    -delta,dir,laser_start);
				VectorMA(e->s.old_origin,-delta,dir,laser_end);
				laser_trace = gi.trace(laser_start,NULL,NULL,laser_end,world,CONTENTS_SOLID|CONTENTS_MONSTER);
				if(laser_trace.ent == ent)
					return false;
				delta += 16;
			}
		}
	}
	if ((trace.fraction == 1) && !jump && canjump && (ent->monsterinfo.jumpdn > 0))
	{
		end[2] = oldorg[2] + move[2] - ent->monsterinfo.jumpdn;
		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID | MASK_WATER);
		if(trace.fraction < 1 && (trace.plane.normal[2] > 0.9) && (trace.contents & MASK_SOLID) && (neworg[2] - 16 > trace.endpos[2]))
		{
			if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER)))
				jump = -1;
		}
	}


	if ((trace.fraction == 1) && !jump)
	{
		// if monster had the ground pulled out, go ahead and fall
		if ( ent->flags & FL_PARTIALGROUND )
		{
			VectorAdd (ent->s.origin, move, ent->s.origin);
			if (relink)
			{
				gi.linkentity (ent);
				G_TouchTriggers (ent);
			}
			ent->groundentity = NULL;
			return true;
		}
		return false;		// walked off an edge
	}

	// check point traces down for dangling corners
	VectorCopy (trace.endpos, ent->s.origin);

	if(!jump)
	{
		qboolean	skip = false;
		// if monster CAN jump down, and a position just a bit forward would be 
		// a good jump-down spot, allow (briefly) !M_CheckBottom
		if (canjump && target && (target->s.origin[2] < ent->s.origin[2]) && (ent->monsterinfo.jumpdn > 0))
		{
			vec3_t		p1, p2;
			trace_t		tr;

			VectorMA(oldorg,48,forward,p1);
			tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, p1, ent, MASK_MONSTERSOLID);
			if(tr.fraction == 1)
			{
				p2[0] = p1[0];
				p2[1] = p1[1];
				p2[2] = p1[2] - ent->monsterinfo.jumpdn;
				tr = gi.trace(p1,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID | MASK_WATER);
				if(tr.fraction < 1 && (tr.plane.normal[2] > 0.9) && (tr.contents & MASK_SOLID) && (p1[2] - 16 > tr.endpos[2]))
				{
					if(!tr.ent || (!tr.ent->client && !(tr.ent->svflags & SVF_MONSTER) && !(tr.ent->svflags & SVF_DEADMONSTER)))
					{
						VectorSubtract(target->s.origin, tr.endpos, dir);
						d2 = VectorLength(dir);
						if(d2 < d1)
							skip = true;
					}
				}
			}

		}
		if (!skip)
		{
			if (!M_CheckBottom (ent))
			{
				if ( ent->flags & FL_PARTIALGROUND )
				{	// entity had floor mostly pulled out from underneath it
					// and is trying to correct
					if (relink)
					{
						gi.linkentity (ent);
						G_TouchTriggers (ent);
					}
					return true;
				}
				VectorCopy (oldorg, ent->s.origin);
				return false;
			}
		}
	}

	if ( ent->flags & FL_PARTIALGROUND )
	{
		ent->flags &= ~FL_PARTIALGROUND;
	}
	ent->groundentity = trace.ent;
	if(trace.ent)
		ent->groundentity_linkcount = trace.ent->linkcount;

// the move is ok
	if(jump)
	{
		VectorScale(move, 10, ent->velocity);
		if(jump > 0)
		{
			ent->monsterinfo.jump(ent);
			ent->velocity[2] = 2.5*jumpheight + 80;
		}
		else
		{
			ent->velocity[2] = max(ent->velocity[2],100);
			if(oldorg[2] - ent->s.origin[2] > 48)
				ent->s.origin[2] = oldorg[2] + ent->velocity[2]*FRAMETIME;
		}
		if(relink)
		{
			gi.linkentity (ent);
			G_TouchTriggers (ent);
		}
	}
	else if (relink)
	{
		gi.linkentity (ent);
		G_TouchTriggers (ent);
	}
	return true;
}
Esempio n. 14
0
qboolean MM_SlideMove
	(
	qboolean gravity
	)

{
	int bumpcount;
	vec3_t dir;
	float d;
	int numplanes;
	vec3_t planes[ 5 ];
	vec3_t clipVelocity;
	int i;
	int j;
	int k;
	trace_t trace;
	vec3_t end;
	float time_left;
	qboolean bBlockEnt;

	if( gravity )
	{
		mm->velocity[ 2 ] = mm->velocity[ 2 ] - mm->frametime * sv_gravity->integer;
		if( mm->groundPlane )
			MM_ClipVelocity( mm->velocity, mm->groundPlaneNormal, mm->velocity, OVERCLIP );
	}

	time_left = mm->frametime;

	if( mm->groundPlane ) {
		numplanes = 1;
		VectorCopy( mm->groundPlaneNormal, planes[ 0 ] );
	} else {
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( mm->velocity, planes[ numplanes ] );
	numplanes++;

	for( bumpcount = 0; bumpcount < 4; bumpcount++ )
	{
		// calculate position we are trying to move to
		VectorMA( mm->origin, time_left, mm->velocity, end );

		// see if we can make it there
		gi.Trace( &trace, mm->origin, mm->mins, mm->maxs, end, mm->entityNum, mm->tracemask, qtrue, qfalse );

		if( trace.allsolid )
			break;

		if( trace.fraction > 0 ) {
			// actually covered some distance
			VectorCopy( trace.endpos, mm->origin );
		}

		if( trace.fraction == 1 )
			return bumpcount != 0;

		// save entity for contact
		bBlockEnt = MM_AddTouchEnt( trace.entityNum );

		if( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL )
		{
			if( trace.plane.normal[ 2 ] > -0.999f && bBlockEnt && mm->groundPlane )
			{
				if( !mm->hit_obstacle )
				{
					mm->hit_obstacle = true;
					VectorCopy( mm->origin, mm->hit_origin );
				}

				VectorAdd( mm->obstacle_normal, trace.plane.normal, mm->obstacle_normal );
			}
		}
		else
		{
			memcpy( &mml.groundTrace, &trace, sizeof( mml.groundTrace ) );
			mml.validGroundTrace = true;
		}

		time_left -= time_left * trace.fraction;

		if( numplanes >= MAX_CLIP_PLANES )
		{
			VectorClear( mm->velocity );
			return qtrue;
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		for( i = 0; i < numplanes; i++ )
		{
			if( DotProduct( trace.plane.normal, planes[ i ] ) > 0.99 )
			{
				VectorAdd( trace.plane.normal, mm->velocity, mm->velocity );
				break;
			}
		}

		if( i >= numplanes )
		{
			//
			// modify velocity so it parallels all of the clip planes
			//

			// find a plane that it enters
			for( i = 0; i < numplanes; i++ )
			{
				if( DotProduct( mm->velocity, planes[ i ] ) >= 0.1 ) {
					continue;		// move doesn't interact with the plane
				}

				// slide along the plane
				MM_ClipVelocity( mm->velocity, planes[ i ], clipVelocity, OVERCLIP );

				// see if there is a second plane that the new move enters
				for( j = 0; j < numplanes; j++ )
				{
					if( j == i ) {
						continue;
					}

					// slide along the plane
					MM_ClipVelocity( mm->velocity, planes[ j ], clipVelocity, OVERCLIP );

					if( DotProduct( clipVelocity, planes[ j ] ) >= 0.0f ) {
						continue;		// move doesn't interact with the plane
					}

					// slide the original velocity along the crease
					CrossProduct( planes[ i ], planes[ j ], dir );
					VectorNormalize( dir );
					d = DotProduct( dir, mm->velocity );
					VectorScale( dir, d, clipVelocity );

					// see if there is a third plane the the new move enters
					for( k = 0; k < numplanes; k++ )
					{
						if( k == i || k == j ) {
							continue;
						}

						if( DotProduct( clipVelocity, planes[ k ] ) >= 0.1f ) {
							continue;		// move doesn't interact with the plane
						}

						// stop dead at a tripple plane interaction
						VectorClear( mm->velocity );
						return qtrue;
					}
				}

				// if we have fixed all interactions, try another move
				VectorCopy( clipVelocity, mm->velocity );
				break;
			}
		}
	}

	if( mm->velocity[ 0 ] || mm->velocity[ 1 ] )
	{
		if( mm->groundPlane )
		{
			VectorCopy( mm->velocity, dir );
			VectorNegate( dir, dir );
			VectorNormalize( dir );

			if( MM_AddTouchEnt( trace.entityNum ) )
			{
				if( !mm->hit_obstacle )
				{
					mm->hit_obstacle = true;
					VectorCopy( mm->origin, mm->hit_origin );
				}

				VectorAdd( mm->obstacle_normal, dir, mm->obstacle_normal );
			}
		}

		VectorClear( mm->velocity );
		return true;
	}

	mm->velocity[ 2 ] = 0;
	return false;
}
Esempio n. 15
0
//	Handles all the complicated wrapping and degenerate cases.
static void MakeMeshNormals( int width, int height, idWorldVertex ctrl[ MAX_GRID_SIZE ][ MAX_GRID_SIZE ] ) {
	static int neighbors[ 8 ][ 2 ] =
	{
		{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
	};

	bool wrapWidth = true;
	for ( int i = 0; i < height; i++ ) {
		float len = ( ctrl[ i ][ 0 ].xyz - ctrl[ i ][ width - 1 ].xyz ).LengthSqr();
		if ( len > 1.0 ) {
			wrapWidth = false;
			break;
		}
	}

	bool wrapHeight = true;
	for ( int i = 0; i < width; i++ ) {
		float len = ( ctrl[ 0 ][ i ].xyz - ctrl[ height - 1 ][ i ].xyz ).LengthSqr();
		if ( len > 1.0 ) {
			wrapHeight = false;
			break;
		}
	}

	for ( int i = 0; i < width; i++ ) {
		for ( int j = 0; j < height; j++ ) {
			int count = 0;
			idWorldVertex& dv = ctrl[ j ][ i ];
			idVec3 base = dv.xyz;
			vec3_t around[ 8 ];
			bool good[ 8 ];
			for ( int k = 0; k < 8; k++ ) {
				VectorClear( around[ k ] );
				good[ k ] = false;

				for ( int dist = 1; dist <= 3; dist++ ) {
					int x = i + neighbors[ k ][ 0 ] * dist;
					int y = j + neighbors[ k ][ 1 ] * dist;
					if ( wrapWidth ) {
						if ( x < 0 ) {
							x = width - 1 + x;
						} else if ( x >= width ) {
							x = 1 + x - width;
						}
					}
					if ( wrapHeight ) {
						if ( y < 0 ) {
							y = height - 1 + y;
						} else if ( y >= height ) {
							y = 1 + y - height;
						}
					}

					if ( x < 0 || x >= width || y < 0 || y >= height ) {
						break;					// edge of patch
					}
					idVec3 temp = ctrl[ y ][ x ].xyz - base;
					vec3_t oldtemp;
					temp.ToOldVec3( oldtemp );
					if ( VectorNormalize2( oldtemp, oldtemp ) == 0 ) {
						continue;				// degenerate edge, get more dist
					} else {
						good[ k ] = true;
						VectorCopy( oldtemp, around[ k ] );
						break;					// good edge
					}
				}
			}

			vec3_t sum;
			VectorClear( sum );
			for ( int k = 0; k < 8; k++ ) {
				if ( !good[ k ] || !good[ ( k + 1 ) & 7 ] ) {
					continue;	// didn't get two points
				}
				vec3_t normal;
				CrossProduct( around[ ( k + 1 ) & 7 ], around[ k ], normal );
				if ( VectorNormalize2( normal, normal ) == 0 ) {
					continue;
				}
				VectorAdd( normal, sum, sum );
				count++;
			}
			if ( count == 0 ) {
				count = 1;
			}
			vec3_t old;
			VectorNormalize2( sum, old );
			dv.normal.FromOldVec3( old );
		}
	}
}
Esempio n. 16
0
qboolean	PM_SlideMove( qboolean gravity ) {
	int			bumpcount, numbumps, extrabumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;
	
	numbumps = 4;
	extrabumps = 0;

	VectorCopy (pm->ps->velocity, primal_velocity);

	if ( gravity ) {
		VectorCopy( pm->ps->velocity, endVelocity );
		endVelocity[2] -= pm->ps->gravity * pml.frametime;
		pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
		primal_velocity[2] = endVelocity[2];
		if ( pml.groundPlane ) {
			// slide along the ground plane
			PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
				pm->ps->velocity, OVERCLIP );
		}
	} else {
		VectorClear( endVelocity );
	}

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane ) {
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[0] );
	} else {
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[numplanes] );
	numplanes++;

	for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {

		// calculate position we are trying to move to
		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

		// see if we can make it there
		PM_TraceAll( &trace, pm->ps->origin, end );
		if ( pm->debugLevel > 1 ) {
			Com_Printf("%i:%d %d (%f %f %f)\n",
				c_pmove, trace.allsolid, trace.startsolid,
				trace.endpos[0],
				trace.endpos[1],
				trace.endpos[2]
			);
		}

		if (trace.allsolid) {
			// entity is completely trapped in another solid
			pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
			return qtrue;
		}

		if (trace.fraction > 0) {
			// actually covered some distance
			VectorCopy (trace.endpos, pm->ps->origin);
		}

		if (trace.fraction == 1) {
			 break;		// moved the entire distance
		}

		// save entity for contact
		PM_AddTouchEnt( trace.entityNum );

		time_left -= time_left * trace.fraction;

		if (numplanes >= MAX_CLIP_PLANES) {
			// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return qtrue;
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		for ( i = 0 ; i < numplanes ; i++ ) {
			if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
				if ( extrabumps <= 0 ) {
					VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
					extrabumps++;
					numbumps++;

					if ( pm->debugLevel )
						Com_Printf( "%i:planevelocitynudge\n", c_pmove );
				} else {
					// zinx - if it happens again, nudge the origin instead,
					// and trace it, to make sure we don't end up in a solid

					VectorAdd( pm->ps->origin, trace.plane.normal, end );
					PM_TraceAll( &trace, pm->ps->origin, end );
					VectorCopy( trace.endpos, pm->ps->origin );

					if ( pm->debugLevel )
						Com_Printf( "%i:planeoriginnudge\n", c_pmove );
				}
				break;
			}
		}
		if ( i < numplanes ) {
			continue;
		}
		VectorCopy (trace.plane.normal, planes[numplanes]);
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) {
			into = DotProduct( pm->ps->velocity, planes[i] );
			if ( into >= 0.1 ) {
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) {
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

			// slide along the plane
			PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

			// see if there is a second plane that the new move enters
			for ( j = 0 ; j < numplanes ; j++ ) {
				if ( j == i ) {
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the new move enters
				for ( k = 0 ; k < numplanes ; k++ ) {
					if ( k == i || k == j ) {
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a tripple plane interaction
					VectorClear( pm->ps->velocity );
					return qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
	}

	if ( gravity ) {
		VectorCopy( endVelocity, pm->ps->velocity );
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time ) {
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

	return ( bumpcount != 0 ) ? qtrue : qfalse;
}
Esempio n. 17
0
/*
MakeTextureMatrix()
generates a texture projection matrix for a triangle
returns qfalse if a texture matrix cannot be created
*/
static qboolean MakeTextureMatrix( vec4_t texMat[ 2 ], vec4_t projection, decalVert_t *a, decalVert_t *b, decalVert_t *c )
{
	int     i, j;
	float   bb, s, t, d;
	vec3_t  pa, pb, pc;
	vec3_t  bary, origin, xyz;
	vec3_t  vecs[ 3 ], axis[ 3 ], lengths;

	/* project triangle onto plane of projection */
	d = DotProduct( a->xyz, projection ) - projection[ 3 ];
	VectorMA( a->xyz, -d, projection, pa );
	d = DotProduct( b->xyz, projection ) - projection[ 3 ];
	VectorMA( b->xyz, -d, projection, pb );
	d = DotProduct( c->xyz, projection ) - projection[ 3 ];
	VectorMA( c->xyz, -d, projection, pc );

	/* calculate barycentric basis for the triangle */
	bb = ( b->st[ 0 ] - a->st[ 0 ] ) * ( c->st[ 1 ] - a->st[ 1 ] ) - ( c->st[ 0 ] - a->st[ 0 ] ) * ( b->st[ 1 ] - a->st[ 1 ] );

	if ( fabs( bb ) < 0.00000001f )
	{
		return qfalse;
	}

	/* calculate texture origin */
	s = 0.0f;
	t = 0.0f;
	bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
	bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
	bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;

	origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
	origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
	origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];

	/* calculate s vector */
	s = 1.0f;
	t = 0.0f;
	bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
	bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
	bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;

	xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
	xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
	xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];

	VectorSubtract( xyz, origin, vecs[ 0 ] );

	/* calculate t vector */
	s = 0.0f;
	t = 1.0f;
	bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
	bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
	bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;

	xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
	xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
	xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];

	VectorSubtract( xyz, origin, vecs[ 1 ] );

	/* calculate r vector */
	VectorScale( projection, -1.0f, vecs[ 2 ] );

	/* calculate transform axis */
	for ( i = 0; i < 3; i++ )
	{
		lengths[ i ] = VectorNormalize2( vecs[ i ], axis[ i ] );
	}

	for ( i = 0; i < 2; i++ )
	{
		for ( j = 0; j < 3; j++ )
		{
			texMat[ i ][ j ] = lengths[ i ] > 0.0f ? ( axis[ i ][ j ] / lengths[ i ] ) : 0.0f;
		}
	}

	texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( pa, texMat[ 0 ] );
	texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( pa, texMat[ 1 ] );

	/* disco */
	return qtrue;
}
Esempio n. 18
0
//===========================================================================
// predicts the movement
// assumes regular bounding box sizes
// NOTE: out of water jumping is not included
// NOTE: grappling hook is not included
//
// Parameter:				origin			: origin to start with
//								presencetype	: presence type to start with
//								velocity			: velocity to start with
//								cmdmove			: client command movement
//								cmdframes		: number of frame cmdmove is valid
//								maxframes		: maximum number of predicted frames
//								frametime		: duration of one predicted frame
//								stopevent		: events that stop the prediction
//						stopareanum		: stop as soon as entered this area
// Returns:					aas_clientmove_t
// Changes Globals:		-
//===========================================================================
int AAS_PredictClientMovement( struct aas_clientmove_s *move,
							   int entnum, vec3_t origin,

#if !defined RTCW_ET
							   int presencetype, int onground,
#else
							   int hitent, int onground,
#endif // RTCW_XX

							   vec3_t velocity, vec3_t cmdmove,
							   int cmdframes,
							   int maxframes, float frametime,
							   int stopevent, int stopareanum, int visualize ) {
	float sv_friction, sv_stopspeed, sv_gravity, sv_waterfriction;
	float sv_watergravity;
	float sv_walkaccelerate, sv_airaccelerate, sv_swimaccelerate;
	float sv_maxwalkvelocity, sv_maxcrouchvelocity, sv_maxswimvelocity;
	float sv_maxstep, sv_maxsteepness, sv_jumpvel, friction;
	float gravity, delta, maxvel, wishspeed, accelerate;
	//float velchange, newvel;
	int n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum;
	int areas[20], numareas;

#if !defined RTCW_ET
	vec3_t points[20];
	vec3_t org, end, feet, start, stepend, lastorg, wishdir;
	vec3_t frame_test_vel, old_frame_test_vel, left_test_vel;
	vec3_t up = {0, 0, 1};
	aas_plane_t *plane, *plane2;
	aas_trace_t trace, steptrace;
#else
	vec3_t points[20], mins, maxs;
	vec3_t org, end, feet, start, stepend, lastorg, wishdir;
	vec3_t frame_test_vel, old_frame_test_vel, left_test_vel, savevel;
	vec3_t up = {0, 0, 1};
	cplane_t *plane, *plane2, *lplane;
	//aas_trace_t trace, steptrace;
	bsp_trace_t trace, steptrace;

	if ( visualize ) {

// These debugging tools are not currently available in bspc. Mad Doctor I, 1/27/2003.
#ifndef BSPC
		AAS_ClearShownPolygons();
		AAS_ClearShownDebugLines();
#endif

	}

	// don't let us succeed on interaction with area 0
	if ( stopareanum == 0 ) {
		stopevent &= ~( SE_ENTERAREA | SE_HITGROUNDAREA );
	}
#endif // RTCW_XX


	if ( frametime <= 0 ) {
		frametime = 0.1;
	}
	//
	sv_friction = aassettings.sv_friction;
	sv_stopspeed = aassettings.sv_stopspeed;
	sv_gravity = aassettings.sv_gravity;
	sv_waterfriction = aassettings.sv_waterfriction;
	sv_watergravity = aassettings.sv_watergravity;
	sv_maxwalkvelocity = aassettings.sv_maxwalkvelocity; // * frametime;
	sv_maxcrouchvelocity = aassettings.sv_maxcrouchvelocity; // * frametime;
	sv_maxswimvelocity = aassettings.sv_maxswimvelocity; // * frametime;
	sv_walkaccelerate = aassettings.sv_walkaccelerate;
	sv_airaccelerate = aassettings.sv_airaccelerate;
	sv_swimaccelerate = aassettings.sv_swimaccelerate;
	sv_maxstep = aassettings.sv_maxstep;
	sv_maxsteepness = aassettings.sv_maxsteepness;
	sv_jumpvel = aassettings.sv_jumpvel * frametime;
	//
	memset( move, 0, sizeof( aas_clientmove_t ) );

#if !defined RTCW_ET
	memset( &trace, 0, sizeof( aas_trace_t ) );
#else
	memset( &trace, 0, sizeof( bsp_trace_t ) );
	AAS_PresenceTypeBoundingBox( PRESENCE_NORMAL, mins, maxs );
#endif // RTCW_XX

	//start at the current origin
	VectorCopy( origin, org );
	org[2] += 0.25;

#if defined RTCW_ET
	// test this position, if it's in solid, move it up to adjust for capsules
	//trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum);
	trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
	while ( trace.startsolid ) {
		org[2] += 8;
		//trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum);
		trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
		if ( trace.startsolid && ( org[2] - origin[2] > 16 ) ) {
			move->stopevent = SE_NONE;
			return qfalse;
		}
	}
#endif // RTCW_XX

	//velocity to test for the first frame
	VectorScale( velocity, frametime, frame_test_vel );
	//
	jump_frame = -1;

#if defined RTCW_ET
	lplane = NULL;
#endif // RTCW_XX

	//predict a maximum of 'maxframes' ahead
	for ( n = 0; n < maxframes; n++ )
	{
		swimming = AAS_Swimming( org );
		//get gravity depending on swimming or not
		gravity = swimming ? sv_watergravity : sv_gravity;
		//apply gravity at the START of the frame
		frame_test_vel[2] = frame_test_vel[2] - ( gravity * 0.1 * frametime );
		//if on the ground or swimming
		if ( onground || swimming ) {
			friction = swimming ? sv_friction : sv_waterfriction;
			//apply friction
			VectorScale( frame_test_vel, 1 / frametime, frame_test_vel );
			AAS_ApplyFriction( frame_test_vel, friction, sv_stopspeed, frametime );
			VectorScale( frame_test_vel, frametime, frame_test_vel );
		} //end if
		crouch = qfalse;
		//apply command movement

#if !defined RTCW_ET
		if ( n < cmdframes ) {
#else
		if ( cmdframes < 0 ) {
			// cmdmove is the destination, we should keep moving towards it
			VectorSubtract( cmdmove, org, wishdir );
			VectorNormalize( wishdir );
			VectorScale( wishdir, sv_maxwalkvelocity, wishdir );
			VectorCopy( frame_test_vel, savevel );
			VectorScale( wishdir, frametime, frame_test_vel );
			if ( !swimming ) {
				frame_test_vel[2] = savevel[2];
			}
		} else if ( n < cmdframes ) {
#endif // RTCW_XX

			ax = 0;
			maxvel = sv_maxwalkvelocity;
			accelerate = sv_airaccelerate;
			VectorCopy( cmdmove, wishdir );
			if ( onground ) {
				if ( cmdmove[2] < -300 ) {
					crouch = qtrue;
					maxvel = sv_maxcrouchvelocity;
				} //end if
				  //if not swimming and upmove is positive then jump
				if ( !swimming && cmdmove[2] > 1 ) {
					//jump velocity minus the gravity for one frame + 5 for safety
					frame_test_vel[2] = sv_jumpvel - ( gravity * 0.1 * frametime ) + 5;
					jump_frame = n;
					//jumping so air accelerate
					accelerate = sv_airaccelerate;
				} //end if
				else
				{
					accelerate = sv_walkaccelerate;
				} //end else
				ax = 2;
			} //end if
			if ( swimming ) {
				maxvel = sv_maxswimvelocity;
				accelerate = sv_swimaccelerate;
				ax = 3;
			} //end if
			else
			{
				wishdir[2] = 0;
			} //end else
			  //
			wishspeed = VectorNormalize( wishdir );
			if ( wishspeed > maxvel ) {
				wishspeed = maxvel;
			}
			VectorScale( frame_test_vel, 1 / frametime, frame_test_vel );
			AAS_Accelerate( frame_test_vel, frametime, wishdir, wishspeed, accelerate );
			VectorScale( frame_test_vel, frametime, frame_test_vel );
			/*
			for (i = 0; i < ax; i++)
			{
				velchange = (cmdmove[i] * frametime) - frame_test_vel[i];
				if (velchange > sv_maxacceleration) velchange = sv_maxacceleration;
				else if (velchange < -sv_maxacceleration) velchange = -sv_maxacceleration;
				newvel = frame_test_vel[i] + velchange;
				//
				if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel;
				else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel;
				else frame_test_vel[i] = newvel;
			} //end for
			*/
		} //end if

#if !defined RTCW_ET
		if ( crouch ) {
			presencetype = PRESENCE_CROUCH;
		} //end if
		else if ( presencetype == PRESENCE_CROUCH ) {
			if ( AAS_PointPresenceType( org ) & PRESENCE_NORMAL ) {
				presencetype = PRESENCE_NORMAL;
			} //end if
		} //end else
#else
		  //if (crouch)
		  //{
		  //	presencetype = PRESENCE_CROUCH;
		  //} //end if
		  //else if (presencetype == PRESENCE_CROUCH)
		  //{
		  //	if (AAS_PointPresenceType(org) & PRESENCE_NORMAL)
		  //	{
		  //		presencetype = PRESENCE_NORMAL;
		  //	} //end if
		  //} //end else
#endif // RTCW_XX

		  //save the current origin
		VectorCopy( org, lastorg );
		//move linear during one frame
		VectorCopy( frame_test_vel, left_test_vel );
		j = 0;
		do
		{
			VectorAdd( org, left_test_vel, end );
			//trace a bounding box

#if !defined RTCW_ET
			trace = AAS_TraceClientBBox( org, end, presencetype, entnum );
#else
			//trace = AAS_TraceClientBBox(org, end, PRESENCE_NORMAL, entnum);
			trace = AAS_Trace( org, mins, maxs, end, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
#endif // RTCW_XX

			//
//#ifdef AAS_MOVE_DEBUG
			if ( visualize ) {

#if !defined RTCW_ET
				if ( trace.startsolid ) {
					botimport.Print( PRT_MESSAGE, "PredictMovement: start solid\n" );
				}
#else
				//if (trace.startsolid)
				//botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n");
#endif // RTCW_XX

				AAS_DebugLine( org, trace.endpos, LINECOLOR_RED );
			} //end if
//#endif //AAS_MOVE_DEBUG
			//

#if defined RTCW_ET
			if ( stopevent & SE_HITENT ) {
				if ( trace.fraction < 1.0 && trace.ent == hitent ) {
					areanum = AAS_PointAreaNum( org );
					VectorCopy( org, move->endpos );
					VectorScale( frame_test_vel, 1 / frametime, move->velocity );
					move->trace = trace;
					move->stopevent = SE_HITENT;
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
					move->endcontents = 0;
					move->time = n * frametime;
					move->frames = n;
					return qtrue;
				}
			}
#endif // RTCW_XX

			if ( stopevent & SE_ENTERAREA ) {
				numareas = AAS_TraceAreas( org, trace.endpos, areas, points, 20 );
				for ( i = 0; i < numareas; i++ )
				{
					if ( areas[i] == stopareanum ) {
						VectorCopy( points[i], move->endpos );
						VectorScale( frame_test_vel, 1 / frametime, move->velocity );
						move->trace = trace;
						move->stopevent = SE_ENTERAREA;

#if !defined RTCW_ET
						move->presencetype = presencetype;
#else
						move->presencetype = ( *aasworld ).areasettings[areas[i]].presencetype;
#endif // RTCW_XX

						move->endcontents = 0;
						move->time = n * frametime;
						move->frames = n;
						return qtrue;
					} //end if
				} //end for
			} //end if

#if defined RTCW_ET
			if ( stopevent & SE_STUCK ) {
				if ( trace.fraction < 1.0 ) {
					plane = &trace.plane;
					//if (Q_fabs(plane->normal[2]) <= sv_maxsteepness) {
					VectorNormalize2( frame_test_vel, wishdir );
					if ( DotProduct( plane->normal, wishdir ) < -0.8 ) {
						areanum = AAS_PointAreaNum( org );
						VectorCopy( org, move->endpos );
						VectorScale( frame_test_vel, 1 / frametime, move->velocity );
						move->trace = trace;
						move->stopevent = SE_STUCK;
						move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
						move->endcontents = 0;
						move->time = n * frametime;
						move->frames = n;
						return qtrue;
					}
				}
			}
#endif // RTCW_XX

			  //move the entity to the trace end point
			VectorCopy( trace.endpos, org );
			//if there was a collision
			if ( trace.fraction < 1.0 ) {
				//get the plane the bounding box collided with

#if !defined RTCW_ET
				plane = AAS_PlaneFromNum( trace.planenum );
#else
				plane = &trace.plane;
#endif // RTCW_XX

				//
				if ( stopevent & SE_HITGROUNDAREA ) {
					if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) {
						VectorCopy( org, start );
						start[2] += 0.5;

#if !defined RTCW_ET
						if ( AAS_PointAreaNum( start ) == stopareanum ) {
#else
						if ( ( stopareanum < 0 && AAS_PointAreaNum( start ) ) || ( AAS_PointAreaNum( start ) == stopareanum ) ) {
#endif // RTCW_XX

							VectorCopy( start, move->endpos );
							VectorScale( frame_test_vel, 1 / frametime, move->velocity );
							move->trace = trace;
							move->stopevent = SE_HITGROUNDAREA;

#if !defined RTCW_ET
							move->presencetype = presencetype;
#else
							move->presencetype = ( *aasworld ).areasettings[stopareanum].presencetype;
#endif // RTCW_XX

							move->endcontents = 0;
							move->time = n * frametime;
							move->frames = n;
							return qtrue;
						} //end if
					} //end if
				} //end if
				  //assume there's no step
				step = qfalse;
				//if it is a vertical plane and the bot didn't jump recently
				if ( plane->normal[2] == 0 && ( jump_frame < 0 || n - jump_frame > 2 ) ) {
					//check for a step
					VectorMA( org, -0.25, plane->normal, start );
					VectorCopy( start, stepend );
					start[2] += sv_maxstep;

#if !defined RTCW_ET
					steptrace = AAS_TraceClientBBox( start, stepend, presencetype, entnum );
#else
					//steptrace = AAS_TraceClientBBox(start, stepend, PRESENCE_NORMAL, entnum);
					steptrace = AAS_Trace( start, mins, maxs, stepend, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
#endif // RTCW_XX

					//
					if ( !steptrace.startsolid ) {

#if !defined RTCW_ET
						plane2 = AAS_PlaneFromNum( steptrace.planenum );
#else
						plane2 = &steptrace.plane;
#endif // RTCW_XX

						if ( DotProduct( plane2->normal, up ) > sv_maxsteepness ) {
							VectorSubtract( end, steptrace.endpos, left_test_vel );
							left_test_vel[2] = 0;
							frame_test_vel[2] = 0;
//#ifdef AAS_MOVE_DEBUG
							if ( visualize ) {
								if ( steptrace.endpos[2] - org[2] > 0.125 ) {
									VectorCopy( org, start );
									start[2] = steptrace.endpos[2];
									AAS_DebugLine( org, start, LINECOLOR_BLUE );
								} //end if
							} //end if
//#endif //AAS_MOVE_DEBUG
							org[2] = steptrace.endpos[2];
							step = qtrue;
						} //end if
					} //end if
				} //end if
				  //
				if ( !step ) {
					//velocity left to test for this frame is the projection
					//of the current test velocity into the hit plane
					VectorMA( left_test_vel, -DotProduct( left_test_vel, plane->normal ),
							  plane->normal, left_test_vel );

#if defined RTCW_ET
					// RF: from PM_SlideMove()
					// if this is the same plane we hit before, nudge velocity
					// out along it, which fixes some epsilon issues with
					// non-axial planes
					if ( lplane && DotProduct( lplane->normal, plane->normal ) > 0.99 ) {
						VectorAdd( plane->normal, left_test_vel, left_test_vel );
					}
					lplane = plane;
#endif // RTCW_XX

					//store the old velocity for landing check
					VectorCopy( frame_test_vel, old_frame_test_vel );
					//test velocity for the next frame is the projection
					//of the velocity of the current frame into the hit plane
					VectorMA( frame_test_vel, -DotProduct( frame_test_vel, plane->normal ),
							  plane->normal, frame_test_vel );
					//check for a landing on an almost horizontal floor
					if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) {
						onground = qtrue;
					} //end if
					if ( stopevent & SE_HITGROUNDDAMAGE ) {
						delta = 0;
						if ( old_frame_test_vel[2] < 0 &&
							 frame_test_vel[2] > old_frame_test_vel[2] &&
							 !onground ) {
							delta = old_frame_test_vel[2];
						} //end if
						else if ( onground ) {
							delta = frame_test_vel[2] - old_frame_test_vel[2];
						} //end else
						if ( delta ) {
							delta = delta * 10;
							delta = delta * delta * 0.0001;
							if ( swimming ) {
								delta = 0;
							}
							// never take falling damage if completely underwater
							/*
							if (ent->waterlevel == 3) return;
							if (ent->waterlevel == 2) delta *= 0.25;
							if (ent->waterlevel == 1) delta *= 0.5;
							*/
							if ( delta > 40 ) {
								VectorCopy( org, move->endpos );
								VectorCopy( frame_test_vel, move->velocity );
								move->trace = trace;
								move->stopevent = SE_HITGROUNDDAMAGE;

#if !defined RTCW_ET
								move->presencetype = presencetype;
#else
								areanum = AAS_PointAreaNum( org );
								if ( areanum ) {
									move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
								}
#endif // RTCW_XX

								move->endcontents = 0;
								move->time = n * frametime;
								move->frames = n;
								return qtrue;
							} //end if
						} //end if
					} //end if
				} //end if
			} //end if
			  //extra check to prevent endless loop
			if ( ++j > 20 ) {
				return qfalse;
			}
			//while there is a plane hit
		} while ( trace.fraction < 1.0 );
		//if going down
		if ( frame_test_vel[2] <= 10 ) {
			//check for a liquid at the feet of the bot
			VectorCopy( org, feet );
			feet[2] -= 22;
			pc = AAS_PointContents( feet );
			//get event from pc
			event = SE_NONE;
			if ( pc & CONTENTS_LAVA ) {
				event |= SE_ENTERLAVA;
			}
			if ( pc & CONTENTS_SLIME ) {
				event |= SE_ENTERSLIME;
			}
			if ( pc & CONTENTS_WATER ) {
				event |= SE_ENTERWATER;
			}
			//
			areanum = AAS_PointAreaNum( org );
			if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_LAVA ) {
				event |= SE_ENTERLAVA;
			}
			if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_SLIME ) {
				event |= SE_ENTERSLIME;
			}
			if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_WATER ) {
				event |= SE_ENTERWATER;
			}
			//if in lava or slime
			if ( event & stopevent ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->stopevent = event & stopevent;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
#endif // RTCW_XX

				move->endcontents = pc;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
		  //

#if !defined RTCW_ET
		onground = AAS_OnGround( org, presencetype, entnum );
#else
		onground = AAS_OnGround( org, PRESENCE_NORMAL, entnum );
#endif // RTCW_XX

		//if onground and on the ground for at least one whole frame
		if ( onground ) {
			if ( stopevent & SE_HITGROUND ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->trace = trace;
				move->stopevent = SE_HITGROUND;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				areanum = AAS_PointAreaNum( org );
				if ( areanum ) {
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
				}
#endif // RTCW_XX

				move->endcontents = 0;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
		else if ( stopevent & SE_LEAVEGROUND ) {
			VectorCopy( org, move->endpos );
			VectorScale( frame_test_vel, 1 / frametime, move->velocity );
			move->trace = trace;
			move->stopevent = SE_LEAVEGROUND;

#if !defined RTCW_ET
			move->presencetype = presencetype;
#else
			areanum = AAS_PointAreaNum( org );
			if ( areanum ) {
				move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
			}
#endif // RTCW_XX

			move->endcontents = 0;
			move->time = n * frametime;
			move->frames = n;
			return qtrue;
		} //end else if
		else if ( stopevent & SE_GAP ) {

#if !defined RTCW_ET
			aas_trace_t gaptrace;
#else
			bsp_trace_t gaptrace;
#endif // RTCW_XX

			VectorCopy( org, start );
			VectorCopy( start, end );
			end[2] -= 48 + aassettings.sv_maxbarrier;

#if !defined RTCW_ET
			gaptrace = AAS_TraceClientBBox( start, end, PRESENCE_CROUCH, -1 );
#else
			//gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
			gaptrace = AAS_Trace( start, mins, maxs, end, -1, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
#endif // RTCW_XX

			//if solid is found the bot cannot walk any further and will not fall into a gap
			if ( !gaptrace.startsolid ) {
				//if it is a gap (lower than one step height)
				if ( gaptrace.endpos[2] < org[2] - aassettings.sv_maxstep - 1 ) {
					if ( !( AAS_PointContents( end ) & ( CONTENTS_WATER | CONTENTS_SLIME ) ) ) { //----(SA)	modified since slime is no longer deadly
//					if (!(AAS_PointContents(end) & CONTENTS_WATER))
						VectorCopy( lastorg, move->endpos );
						VectorScale( frame_test_vel, 1 / frametime, move->velocity );
						move->trace = trace;
						move->stopevent = SE_GAP;

#if !defined RTCW_ET
						move->presencetype = presencetype;
#else
						areanum = AAS_PointAreaNum( org );
						if ( areanum ) {
							move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
						}
#endif // RTCW_XX

						move->endcontents = 0;
						move->time = n * frametime;
						move->frames = n;
						return qtrue;
					} //end if
				} //end if
			} //end if
		} //end else if
		if ( stopevent & SE_TOUCHJUMPPAD ) {
			if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_JUMPPAD ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->trace = trace;
				move->stopevent = SE_TOUCHJUMPPAD;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				areanum = AAS_PointAreaNum( org );
				if ( areanum ) {
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
				}
#endif // RTCW_XX

				move->endcontents = 0;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
		if ( stopevent & SE_TOUCHTELEPORTER ) {
			if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_TELEPORTER ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->trace = trace;
				move->stopevent = SE_TOUCHTELEPORTER;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				areanum = AAS_PointAreaNum( org );
				if ( areanum ) {
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
				}
#endif // RTCW_XX

				move->endcontents = 0;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
	} //end for
	  //

#if defined RTCW_ET
	areanum = AAS_PointAreaNum( org );
#endif // RTCW_XX

	VectorCopy( org, move->endpos );
	VectorScale( frame_test_vel, 1 / frametime, move->velocity );
	move->stopevent = SE_NONE;

#if !defined RTCW_ET
	move->presencetype = presencetype;
#else
	move->presencetype = aasworld->areasettings ? aasworld->areasettings[areanum].presencetype : 0;
#endif // RTCW_XX

	move->endcontents = 0;
	move->time = n * frametime;
	move->frames = n;
	//
	return qtrue;
} //end of the function AAS_PredictClientMovement
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_TestMovementPrediction( int entnum, vec3_t origin, vec3_t dir ) {
	vec3_t velocity, cmdmove;
	aas_clientmove_t move;

	VectorClear( velocity );
	if ( !AAS_Swimming( origin ) ) {
		dir[2] = 0;
	}
	VectorNormalize( dir );
	VectorScale( dir, 400, cmdmove );
	cmdmove[2] = 224;
	AAS_ClearShownDebugLines();
	AAS_PredictClientMovement( &move, entnum, origin, PRESENCE_NORMAL, qtrue,
							   velocity, cmdmove, 13, 13, 0.1, SE_HITGROUND, 0, qtrue );    //SE_LEAVEGROUND);
	if ( move.stopevent & SE_LEAVEGROUND ) {
		botimport.Print( PRT_MESSAGE, "leave ground\n" );
	} //end if
} //end of the function TestMovementPrediction
//===========================================================================
// calculates the horizontal velocity needed to perform a jump from start
// to end
//
// Parameter:				zvel		: z velocity for jump
//								start		: start position of jump
//								end		: end position of jump
//								*speed	: returned speed for jump
// Returns:					qfalse if too high or too far from start to end
// Changes Globals:		-
//===========================================================================
int AAS_HorizontalVelocityForJump( float zvel, vec3_t start, vec3_t end, float *velocity ) {
	float sv_gravity, sv_maxvelocity;
	float maxjump, height2fall, t, top;
	vec3_t dir;

	sv_gravity = aassettings.sv_gravity;
	sv_maxvelocity = aassettings.sv_maxvelocity;

	//maximum height a player can jump with the given initial z velocity
	maxjump = 0.5 * sv_gravity * ( zvel / sv_gravity ) * ( zvel / sv_gravity );
	//top of the parabolic jump
	top = start[2] + maxjump;
	//height the bot will fall from the top
	height2fall = top - end[2];
	//if the goal is to high to jump to
	if ( height2fall < 0 ) {
		*velocity = sv_maxvelocity;
		return 0;
	} //end if
	  //time a player takes to fall the height
	t = c::sqrt( height2fall / ( 0.5 * sv_gravity ) );
	//direction from start to end
	VectorSubtract( end, start, dir );
	//calculate horizontal speed
	*velocity = c::sqrt( dir[0] * dir[0] + dir[1] * dir[1] ) / ( t + zvel / sv_gravity );
	//the horizontal speed must be lower than the max speed
	if ( *velocity > sv_maxvelocity ) {
		*velocity = sv_maxvelocity;
		return 0;
	} //end if
	return 1;
} //end of the function AAS_HorizontalVelocityForJump
Esempio n. 19
0
/*
=================
BaseWindingForPlane
=================
*/
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
{
	int		i, x;
	vec_t	max, v;
	vec3_t	org, vright, vup;
	winding_t	*w;
	
// find the major axis

	max = -MAX_MAP_BOUNDS;
	x = -1;
	for (i=0 ; i<3; i++)
	{
		v = fabs(normal[i]);
		if (v > max)
		{
			x = i;
			max = v;
		}
	}
	if (x==-1)
		Com_Error (ERR_DROP, "BaseWindingForPlane: no axis found");
		
	VectorCopy (vec3_origin, vup);	
	switch (x)
	{
	case 0:
	case 1:
		vup[2] = 1;
		break;		
	case 2:
		vup[0] = 1;
		break;		
	}

	v = DotProduct (vup, normal);
	VectorMA (vup, -v, normal, vup);
	VectorNormalize2(vup, vup);
		
	VectorScale (normal, dist, org);
	
	CrossProduct (vup, normal, vright);
	
	VectorScale (vup, MAX_MAP_BOUNDS, vup);
	VectorScale (vright, MAX_MAP_BOUNDS, vright);

// project a really big	axis aligned box onto the plane
	w = AllocWinding (4);
	
	VectorSubtract (org, vright, w->p[0]);
	VectorAdd (w->p[0], vup, w->p[0]);
	
	VectorAdd (org, vright, w->p[1]);
	VectorAdd (w->p[1], vup, w->p[1]);
	
	VectorAdd (org, vright, w->p[2]);
	VectorSubtract (w->p[2], vup, w->p[2]);
	
	VectorSubtract (org, vright, w->p[3]);
	VectorSubtract (w->p[3], vup, w->p[3]);
	
	w->numpoints = 4;
	
	return w;	
}
Esempio n. 20
0
void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace)
{
	// See if the vehicle has crashed into the ground.
	Vehicle_t *pSelfVeh = pEnt->m_pVehicle;
	float magnitude = VectorLength( pm->ps->velocity ) * pSelfVeh->m_pVehicleInfo->mass / 50.0f;
	qboolean forceSurfDestruction = qfalse;
#ifdef _GAME
	gentity_t *hitEnt = trace!=NULL?&g_entities[trace->entityNum]:NULL;

	if (!hitEnt ||
		(pSelfVeh && pSelfVeh->m_pPilot &&
		hitEnt && hitEnt->s.eType == ET_MISSILE && hitEnt->inuse &&
		hitEnt->r.ownerNum == pSelfVeh->m_pPilot->s.number)
		)
	{
		return;
	}

	if ( pSelfVeh//I have a vehicle struct
		&& pSelfVeh->m_iRemovedSurfaces )//vehicle has bits removed
	{//spiralling to our deaths, explode on any solid impact
		if ( hitEnt->s.NPC_class == CLASS_VEHICLE )
		{//hit another vehicle, explode!
			//Give credit to whoever got me into this death spiral state
			gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
			gentity_t *killer = NULL;
			if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
				parent->client->ps.otherKillerTime > level.time)
			{
				gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

				if (potentialKiller->inuse && potentialKiller->client)
				{ //he's valid I guess
					killer = potentialKiller;
				}
			}
			//FIXME: damage hitEnt, some, too?  Our explosion should hurt them some, but...
			G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
			return;
		}
		else if ( !VectorCompare( trace->plane.normal, vec3_origin )
			&& (trace->entityNum == ENTITYNUM_WORLD || hitEnt->r.bmodel ) )
		{//have a valid hit plane and we hit a solid brush
			vec3_t	moveDir;
			float	impactDot;
			VectorCopy( pm->ps->velocity, moveDir );
			VectorNormalize( moveDir );
			impactDot = DotProduct( moveDir, trace->plane.normal );
			if ( impactDot <= -0.7f )//hit rather head-on and hard
			{// Just DIE now
				//Give credit to whoever got me into this death spiral state
				gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
				gentity_t *killer = NULL;
				if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
					parent->client->ps.otherKillerTime > level.time)
				{
					gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

					if (potentialKiller->inuse && potentialKiller->client)
					{ //he's valid I guess
						killer = potentialKiller;
					}
				}
				G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
				return;
			}
		}
	}

	if ( trace->entityNum < ENTITYNUM_WORLD
		&& hitEnt->s.eType == ET_MOVER
		&& hitEnt->s.apos.trType != TR_STATIONARY//rotating
		&& (hitEnt->spawnflags&16) //IMPACT
		&& Q_stricmp( "func_rotating", hitEnt->classname ) == 0 )
	{//hit a func_rotating that is supposed to destroy anything it touches!
		//guarantee the hit will happen, thereby taking off a piece of the ship
		forceSurfDestruction = qtrue;
	}
	else if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
		&& pm->ps->velocity[2] > -100.0f )
#elif defined(_CGAME)
	if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
		&& pm->ps->velocity[2] > -100.0f )
#endif
		/*
	if ( (pSelfVeh->m_ulFlags&VEH_GEARSOPEN)
		&& trace->plane.normal[2] > 0.7f
		&& fabs(pSelfVeh->m_vOrientation[PITCH]) < 0.2f
		&& fabs(pSelfVeh->m_vOrientation[ROLL]) < 0.2f )*/
	{//we're landing, we're cool
		//FIXME: some sort of landing "thump", not the impactFX
		/*
		if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
		{
			vec3_t up = {0,0,1};
#ifdef _GAME
			G_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, up );
#else
			trap->FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, up, -1, -1, qfalse );
#endif
		}
		*/
		//this was annoying me -rww
		//FIXME: this shouldn't even be getting called when the vehicle is at rest!
#ifdef _GAME
		if (hitEnt && (hitEnt->s.eType == ET_PLAYER || hitEnt->s.eType == ET_NPC) && pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
		{ //always smack players
		}
		else
#endif
		{
			return;
		}
	}
	if ( pSelfVeh &&
		(pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER) && //this is kind of weird on tauntauns and atst's..
		(magnitude >= 100||forceSurfDestruction) )
	{
		if ( pEnt->m_pVehicle->m_iHitDebounce < pm->cmd.serverTime
			|| forceSurfDestruction )
		{//a bit of a hack, may conflict with getting shot, but...
			//FIXME: impact sound and effect should be gotten from g_vehicleInfo...?
			//FIXME: should pass in trace.endpos and trace.plane.normal
			vec3_t	vehUp;
#ifdef _CGAME
			bgEntity_t *hitEnt;
#endif

			if ( trace && !pSelfVeh->m_iRemovedSurfaces && !forceSurfDestruction )
			{
				qboolean turnFromImpact = qfalse, turnHitEnt = qfalse;
				float l = pm->ps->speed*0.5f;
				vec3_t	bounceDir;
#ifdef _CGAME
				bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
				if ( (trace->entityNum == ENTITYNUM_WORLD || hitEnt->s.solid == SOLID_BMODEL)//bounce off any brush
					 && !VectorCompare(trace->plane.normal, vec3_origin) )//have a valid plane to bounce off of
				{ //bounce off in the opposite direction of the impact
					if (pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER)
					{
						pm->ps->speed *= pml.frametime;
						VectorCopy(trace->plane.normal, bounceDir);
					}
					else if ( trace->plane.normal[2] >= MIN_LANDING_SLOPE//flat enough to land on
						&& pSelfVeh->m_LandTrace.fraction < 1.0f //ground present
						&& pm->ps->speed <= MIN_LANDING_SPEED )
					{//could land here, don't bounce off, in fact, return altogether!
						return;
					}
					else
					{
						if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
						{
							turnFromImpact = qtrue;
						}
						VectorCopy(trace->plane.normal, bounceDir);
					}
				}
				else if ( pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER )
				{//check for impact with another fighter
#ifdef _CGAME
					bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
					if ( hitEnt->s.NPC_class == CLASS_VEHICLE
						&& hitEnt->m_pVehicle
						&& hitEnt->m_pVehicle->m_pVehicleInfo
						&& hitEnt->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
					{//two vehicles hit each other, turn away from the impact
						turnFromImpact = qtrue;
						turnHitEnt = qtrue;
						#ifdef _GAME
							VectorSubtract( pm->ps->origin, hitEnt->r.currentOrigin, bounceDir );
						#else
							VectorSubtract( pm->ps->origin, hitEnt->s.origin, bounceDir );
						#endif
						VectorNormalize( bounceDir );
					}
				}
				if ( turnFromImpact )
				{//bounce off impact surf and turn away
					vec3_t	pushDir={0}, turnAwayAngles, turnDelta;
					float	turnStrength, pitchTurnStrength, yawTurnStrength;
					vec3_t	moveDir;
					float bounceDot, turnDivider;
					//bounce
					if ( !turnHitEnt )
					{//hit wall
						VectorScale(bounceDir, (pm->ps->speed*0.25f/pSelfVeh->m_pVehicleInfo->mass), pushDir);
					}
					else
					{//hit another fighter
						#ifdef _GAME
							if ( hitEnt->client )
							{
								VectorScale( bounceDir, (pm->ps->speed+hitEnt->client->ps.speed)*0.5f, pushDir );
							}
							else
							{
								VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, pushDir );
							}
						#else
							VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, bounceDir );
						#endif
						VectorScale(pushDir, (l/pSelfVeh->m_pVehicleInfo->mass), pushDir);
						VectorScale(pushDir, 0.1f, pushDir);
					}
					VectorNormalize2( pm->ps->velocity, moveDir );
					bounceDot = DotProduct( moveDir, bounceDir )*-1;
					if ( bounceDot < 0.1f )
					{
						bounceDot = 0.1f;
					}
					VectorScale( pushDir, bounceDot, pushDir );
					VectorAdd(pm->ps->velocity, pushDir, pm->ps->velocity);
					//turn
					turnDivider = (pSelfVeh->m_pVehicleInfo->mass/400.0f);
					if ( turnHitEnt )
					{//don't turn as much when hit another ship
						turnDivider *= 4.0f;
					}
					if ( turnDivider < 0.5f )
					{
						turnDivider = 0.5f;
					}
					turnStrength = (magnitude/2000.0f);
					if ( turnStrength < 0.1f )
					{
						turnStrength = 0.1f;
					}
					else if ( turnStrength > 2.0f )
					{
						turnStrength = 2.0f;
					}
					//get the angles we are going to turn towards
					vectoangles( bounceDir, turnAwayAngles );
					//get the delta from our current angles to those new angles
					AnglesSubtract( turnAwayAngles, pSelfVeh->m_vOrientation, turnDelta );
					//now do pitch
					if ( !bounceDir[2] )
					{//shouldn't be any pitch
					}
					else
					{
						pitchTurnStrength = turnStrength*turnDelta[PITCH];
						if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
						{
							pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
						}
						else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
						{
							pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
						}
						//pSelfVeh->m_vOrientation[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						pSelfVeh->m_vFullAngleVelocity[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
					}
					//now do yaw
					if ( !bounceDir[0]
						&& !bounceDir[1] )
					{//shouldn't be any yaw
					}
					else
					{
						yawTurnStrength = turnStrength*turnDelta[YAW];
						if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
						{
							yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
						}
						else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
						{
							yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
						}
						//pSelfVeh->m_vOrientation[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						pSelfVeh->m_vFullAngleVelocity[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
					}
					/*
					PM_SetPMViewAngle(pm->ps, pSelfVeh->m_vOrientation, &pSelfVeh->m_ucmd);
					if ( pm_entVeh )
					{//I'm a vehicle, so pm_entVeh is actually my pilot
						bgEntity_t *pilot = pm_entVeh;
						if ( !BG_UnrestrainedPitchRoll( pilot->playerState, pSelfVeh ) )
						{
							//set the rider's viewangles to the vehicle's viewangles
							PM_SetPMViewAngle(pilot->playerState, pSelfVeh->m_vOrientation, &pSelfVeh->m_ucmd);
						}
					}
					*/
#ifdef _GAME//server-side, turn the guy we hit away from us, too
					if ( turnHitEnt//make the other guy turn and get pushed
						&& hitEnt->client //must be a valid client
						&& !FighterIsLanded( hitEnt->m_pVehicle, &hitEnt->client->ps )//but not if landed
						&& !(hitEnt->spawnflags&2) )//and not if suspended
					{
						l = hitEnt->client->ps.speed;
						//now bounce *them* away and turn them
						//flip the bounceDir
						VectorScale( bounceDir, -1, bounceDir );
						//do bounce
						VectorScale( bounceDir, (pm->ps->speed+l)*0.5f, pushDir );
						VectorScale(pushDir, (l*0.5f/hitEnt->m_pVehicle->m_pVehicleInfo->mass), pushDir);
						VectorNormalize2( hitEnt->client->ps.velocity, moveDir );
						bounceDot = DotProduct( moveDir, bounceDir )*-1;
						if ( bounceDot < 0.1f )
						{
							bounceDot = 0.1f;
						}
						VectorScale( pushDir, bounceDot, pushDir );
						VectorAdd(hitEnt->client->ps.velocity, pushDir, hitEnt->client->ps.velocity);
						//turn
						turnDivider = (hitEnt->m_pVehicle->m_pVehicleInfo->mass/400.0f);
						if ( turnHitEnt )
						{//don't turn as much when hit another ship
							turnDivider *= 4.0f;
						}
						if ( turnDivider < 0.5f )
						{
							turnDivider = 0.5f;
						}
						//get the angles we are going to turn towards
						vectoangles( bounceDir, turnAwayAngles );
						//get the delta from our current angles to those new angles
						AnglesSubtract( turnAwayAngles, hitEnt->m_pVehicle->m_vOrientation, turnDelta );
						//now do pitch
						if ( !bounceDir[2] )
						{//shouldn't be any pitch
						}
						else
						{
							pitchTurnStrength = turnStrength*turnDelta[PITCH];
							if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
							{
								pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
							}
							else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
							{
								pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
							}
							//hitEnt->m_pVehicle->m_vOrientation[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
							hitEnt->m_pVehicle->m_vFullAngleVelocity[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						}
						//now do yaw
						if ( !bounceDir[0]
							&& !bounceDir[1] )
						{//shouldn't be any yaw
						}
						else
						{
							yawTurnStrength = turnStrength*turnDelta[YAW];
							if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
							{
								yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
							}
							else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
							{
								yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
							}
							//hitEnt->m_pVehicle->m_vOrientation[ROLL] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
							hitEnt->m_pVehicle->m_vFullAngleVelocity[ROLL] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						}
						//NOTE: will these angle changes stick or will they be stomped
						//		when the vehicle goes through its own update and re-grabs
						//		its angles from its pilot...?  Should we do a
						//		SetClientViewAngles on the pilot?
						/*
						SetClientViewAngle( hitEnt, hitEnt->m_pVehicle->m_vOrientation );
						if ( hitEnt->m_pVehicle->m_pPilot
							&& ((gentity_t *)hitEnt->m_pVehicle->m_pPilot)->client )
						{
							SetClientViewAngle( (gentity_t *)hitEnt->m_pVehicle->m_pPilot, hitEnt->m_pVehicle->m_vOrientation );
						}
						*/
					}
#endif
				}
			}

#ifdef _GAME
			if (!hitEnt)
			{
				return;
			}

			AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
			if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
			{
				//G_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp );
				//tempent use bad!
				G_AddEvent((gentity_t *)pEnt, EV_PLAY_EFFECT_ID, pSelfVeh->m_pVehicleInfo->iImpactFX);
			}
			pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
			magnitude /= pSelfVeh->m_pVehicleInfo->toughness * 50.0f;

			if (hitEnt && (hitEnt->s.eType != ET_TERRAIN || !(hitEnt->spawnflags & 1) || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER))
			{ //don't damage the vehicle from terrain that doesn't want to damage vehicles
				if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
				{ //increase the damage...
					float mult = (pSelfVeh->m_vOrientation[PITCH]*0.1f);
					if (mult < 1.0f)
					{
						mult = 1.0f;
					}
					if (hitEnt->inuse && hitEnt->takedamage)
					{ //if the other guy takes damage, don't hurt us a lot for ramming him
						//unless it's a vehicle, then we get 1.5 times damage
						if (hitEnt->s.eType == ET_NPC &&
							hitEnt->s.NPC_class == CLASS_VEHICLE &&
							hitEnt->m_pVehicle)
						{
							mult = 1.5f;
						}
						else
						{
							mult = 0.5f;
						}
					}

					magnitude *= mult;
				}
				pSelfVeh->m_iLastImpactDmg = magnitude;
				//FIXME: what about proper death credit to the guy who shot you down?
				//FIXME: actually damage part of the ship that impacted?
				G_Damage( (gentity_t *)pEnt, NULL, NULL, NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT

				if (pSelfVeh->m_pVehicleInfo->surfDestruction)
				{
					G_FlyVehicleSurfaceDestruction((gentity_t *)pEnt, trace, magnitude, forceSurfDestruction );
				}

				pSelfVeh->m_ulFlags |= VEH_CRASHING;
			}

			if (hitEnt &&
				hitEnt->inuse &&
				hitEnt->takedamage)
			{ //damage this guy because we hit him
				float pmult = 1.0f;
				int finalD;
				gentity_t *attackEnt;

				if ( (hitEnt->s.eType == ET_PLAYER && hitEnt->s.number < MAX_CLIENTS) ||
					 (hitEnt->s.eType == ET_NPC && hitEnt->s.NPC_class != CLASS_VEHICLE) )
				{ //probably a humanoid, or something
					if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
					{ //player die good.. if me fighter
						pmult = 2000.0f;
					}
					else
					{
						pmult = 40.0f;
					}

					if (hitEnt->client &&
						BG_KnockDownable(&hitEnt->client->ps) &&
						G_CanBeEnemy((gentity_t *)pEnt, hitEnt))
					{ //smash!
						if (hitEnt->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
						{
							hitEnt->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
							hitEnt->client->ps.forceHandExtendTime = pm->cmd.serverTime + 1100;
							hitEnt->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
						}

						hitEnt->client->ps.otherKiller = pEnt->s.number;
						hitEnt->client->ps.otherKillerTime = pm->cmd.serverTime + 5000;
						hitEnt->client->ps.otherKillerDebounceTime = pm->cmd.serverTime + 100;

						//add my velocity into his to force him along in the correct direction from impact
						VectorAdd(hitEnt->client->ps.velocity, pm->ps->velocity, hitEnt->client->ps.velocity);
						//upward thrust
						hitEnt->client->ps.velocity[2] += 200.0f;
					}
				}

				if (pSelfVeh->m_pPilot)
				{
					attackEnt = (gentity_t *)pSelfVeh->m_pPilot;
				}
				else
				{
					attackEnt = (gentity_t *)pEnt;
				}

				finalD = magnitude*pmult;
				if (finalD < 1)
				{
					finalD = 1;
				}
				G_Damage( hitEnt, attackEnt, attackEnt, NULL, pm->ps->origin, finalD, 0, MOD_MELEE );//FIXME: MOD_IMPACT
			}
#else	//this is gonna result in "double effects" for the client doing the prediction.
		//it doesn't look bad though. could just use predicted events, but I'm too lazy.
			hitEnt = PM_BGEntForNum(trace->entityNum);

			if (!hitEnt || hitEnt->s.owner != pEnt->s.number)
			{ //don't hit your own missiles!
				AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
				pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
				trap->FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp, -1, -1, qfalse );

				pSelfVeh->m_ulFlags |= VEH_CRASHING;
			}
#endif
		}
	}
}
Esempio n. 21
0
/*
=================
MakeMeshNormals

Handles all the complicated wrapping and degenerate cases
=================
*/
static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
	int		i, j, k, dist;
	vec3_t	normal;
	vec3_t	sum;
	int		count;
	vec3_t	base;
	vec3_t	delta;
	int		x, y;
	drawVert_t	*dv;
	vec3_t		around[8], temp;
	qboolean	good[8];
	qboolean	wrapWidth, wrapHeight;
	float		len;
static	int	neighbors[8][2] = {
	{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
	};

	wrapWidth = qfalse;
	for ( i = 0 ; i < height ; i++ ) {
		VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
		len = VectorLengthSquared( delta );
		if ( len > 1.0 ) {
			break;
		}
	}
	if ( i == height ) {
		wrapWidth = qtrue;
	}

	wrapHeight = qfalse;
	for ( i = 0 ; i < width ; i++ ) {
		VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
		len = VectorLengthSquared( delta );
		if ( len > 1.0 ) {
			break;
		}
	}
	if ( i == width) {
		wrapHeight = qtrue;
	}


	for ( i = 0 ; i < width ; i++ ) {
		for ( j = 0 ; j < height ; j++ ) {
			count = 0;
			dv = &ctrl[j][i];
			VectorCopy( dv->xyz, base );
			for ( k = 0 ; k < 8 ; k++ ) {
				VectorClear( around[k] );
				good[k] = qfalse;

				for ( dist = 1 ; dist <= 3 ; dist++ ) {
					x = i + neighbors[k][0] * dist;
					y = j + neighbors[k][1] * dist;
					if ( wrapWidth ) {
						if ( x < 0 ) {
							x = width - 1 + x;
						} else if ( x >= width ) {
							x = 1 + x - width;
						}
					}
					if ( wrapHeight ) {
						if ( y < 0 ) {
							y = height - 1 + y;
						} else if ( y >= height ) {
							y = 1 + y - height;
						}
					}

					if ( x < 0 || x >= width || y < 0 || y >= height ) {
						break;					// edge of patch
					}
					VectorSubtract( ctrl[y][x].xyz, base, temp );
					if ( VectorNormalize2( temp, temp ) == 0 ) {
						continue;				// degenerate edge, get more dist
					} else {
						good[k] = qtrue;
						VectorCopy( temp, around[k] );
						break;					// good edge
					}
				}
			}

			VectorClear( sum );
			for ( k = 0 ; k < 8 ; k++ ) {
				if ( !good[k] || !good[(k+1)&7] ) {
					continue;	// didn't get two points
				}
				CrossProduct( around[(k+1)&7], around[k], normal );
				if ( VectorNormalize2( normal, normal ) == 0 ) {
					continue;
				}
				VectorAdd( normal, sum, sum );
				count++;
			}
			if ( count == 0 ) {
//printf("bad normal\n");
				count = 1;
			}
			VectorNormalize2( sum, dv->normal );
		}
	}
}
Esempio n. 22
0
qboolean	PM_SlideMove( qboolean gravity ) {
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		normal, planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;
	//qboolean	damageSelf = qtrue;

	numbumps = 4;

	VectorCopy (pm->ps->velocity, primal_velocity);
	VectorCopy (pm->ps->velocity, endVelocity);

	if ( gravity ) {
		endVelocity[2] -= pm->ps->gravity * pml.frametime;
		pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
		primal_velocity[2] = endVelocity[2];
		if ( pml.groundPlane ) {
			if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
			{// slide along the ground plane
				PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
					pm->ps->velocity, OVERCLIP );
			}
		}
	}

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane ) {
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[0] );
		if ( !PM_GroundSlideOkay( planes[0][2] ) )
		{
			planes[0][2] = 0;
			VectorNormalize( planes[0] );
		}
	} else {
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[numplanes] );
	numplanes++;

	for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {

		// calculate position we are trying to move to
		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

		// see if we can make it there
		pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);

		if (trace.allsolid) {
			// entity is completely trapped in another solid
			pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
			return qtrue;
		}

		if (trace.fraction > 0) {
			// actually covered some distance
			VectorCopy (trace.endpos, pm->ps->origin);
		}

		if (trace.fraction == 1) {
			 break;		// moved the entire distance
		}

		// save entity for contact
		PM_AddTouchEnt( trace.entityNum );

		if (pm->ps->clientNum >= MAX_CLIENTS)
		{
			bgEntity_t *pEnt = pm_entSelf;

			if (pEnt && pEnt->s.eType == ET_NPC && pEnt->s.NPC_class == CLASS_VEHICLE &&
				pEnt->m_pVehicle)
			{ //do vehicle impact stuff then
				PM_VehicleImpact(pEnt, &trace);
			}
		}
#ifdef _GAME
		else
		{
			if ( PM_ClientImpact( &trace ) )
			{
				continue;
			}
		}
#endif

		time_left -= time_left * trace.fraction;

		if (numplanes >= MAX_CLIP_PLANES) {
			// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return qtrue;
		}

		VectorCopy( trace.plane.normal, normal );

		if ( !PM_GroundSlideOkay( normal[2] ) )
		{//wall-running
			//never push up off a sloped wall
			normal[2] = 0;
			VectorNormalize( normal );
		}
		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
		{//no sliding if stuck to wall!
			for ( i = 0 ; i < numplanes ; i++ ) {
				if ( VectorCompare( normal, planes[i] ) ) {//DotProduct( normal, planes[i] ) > 0.99 ) {
					VectorAdd( normal, pm->ps->velocity, pm->ps->velocity );
					break;
				}
			}
			if ( i < numplanes ) {
				continue;
			}
		}
		VectorCopy (normal, planes[numplanes]);
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) {
			into = DotProduct( pm->ps->velocity, planes[i] );
			if ( into >= 0.1 ) {
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) {
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

			// slide along the plane
			PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

			// see if there is a second plane that the new move enters
			for ( j = 0 ; j < numplanes ; j++ ) {
				if ( j == i ) {
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the new move enters
				for ( k = 0 ; k < numplanes ; k++ ) {
					if ( k == i || k == j ) {
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a triple plane interaction
					VectorClear( pm->ps->velocity );
					return qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
	}

	if ( gravity ) {
		VectorCopy( endVelocity, pm->ps->velocity );
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time ) {
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

	return ( bumpcount != 0 );
}
Esempio n. 23
0
/*
* CG_AddFragmentedDecal
*/
void CG_AddFragmentedDecal( vec3_t origin, vec3_t dir, float orient, float radius,
						   float r, float g, float b, float a, struct shader_s *shader )
{
	int i, j, c;
	vec3_t axis[3];
	byte_vec4_t color;
	fragment_t *fr, fragments[MAX_TEMPDECAL_FRAGMENTS];
	int numfragments;
	poly_t poly;
	vec4_t verts[MAX_BLOBSHADOW_VERTS];
	static vec4_t t_verts[MAX_TEMPDECAL_VERTS*MAX_TEMPDECALS];
	static vec4_t t_norms[MAX_TEMPDECAL_VERTS*MAX_TEMPDECALS];
	static vec2_t t_stcoords[MAX_TEMPDECAL_VERTS*MAX_TEMPDECALS];
	static byte_vec4_t t_colors[MAX_TEMPDECAL_VERTS*MAX_TEMPDECALS];

	if( radius <= 0 || VectorCompare( dir, vec3_origin ) )
		return; // invalid

	// calculate orientation matrix
	VectorNormalize2( dir, axis[0] );
	PerpendicularVector( axis[1], axis[0] );
	RotatePointAroundVector( axis[2], axis[0], axis[1], orient );
	CrossProduct( axis[0], axis[2], axis[1] );

	numfragments = trap_R_GetClippedFragments( origin, radius, axis, // clip it
		MAX_BLOBSHADOW_VERTS, verts, MAX_TEMPDECAL_FRAGMENTS, fragments );

	// no valid fragments
	if( !numfragments )
		return;

	// clamp and scale colors
	if( r < 0 ) r = 0;else if( r > 1 ) r = 255;else r *= 255;
	if( g < 0 ) g = 0;else if( g > 1 ) g = 255;else g *= 255;
	if( b < 0 ) b = 0;else if( b > 1 ) b = 255;else b *= 255;
	if( a < 0 ) a = 0;else if( a > 1 ) a = 255;else a *= 255;

	color[0] = ( qbyte )( r );
	color[1] = ( qbyte )( g );
	color[2] = ( qbyte )( b );
	color[3] = ( qbyte )( a );
	c = *( int * )color;

	radius = 0.5f / radius;
	VectorScale( axis[1], radius, axis[1] );
	VectorScale( axis[2], radius, axis[2] );

	memset( &poly, 0, sizeof( poly ) );

	for( i = 0, fr = fragments; i < numfragments; i++, fr++ )
	{
		if( fr->numverts <= 0 )
			continue;
		if( cg_numDecalVerts+(unsigned)fr->numverts > sizeof( t_verts ) / sizeof( t_verts[0] ) )
			return;

		poly.shader = shader;
		poly.verts = &t_verts[cg_numDecalVerts];
		poly.normals = &t_norms[cg_numDecalVerts];
		poly.stcoords = &t_stcoords[cg_numDecalVerts];
		poly.colors = &t_colors[cg_numDecalVerts];
		poly.numverts = fr->numverts;
		poly.fognum = fr->fognum;
		cg_numDecalVerts += (unsigned)fr->numverts;

		for( j = 0; j < fr->numverts; j++ )
		{
			vec3_t v;

			Vector4Copy( verts[fr->firstvert+j], poly.verts[j] );
			VectorCopy( axis[0], poly.normals[j] ); poly.normals[j][3] = 0;
			VectorSubtract( poly.verts[j], origin, v );
			poly.stcoords[j][0] = DotProduct( v, axis[1] ) + 0.5f;
			poly.stcoords[j][1] = DotProduct( v, axis[2] ) + 0.5f;
			*( int * )poly.colors[j] = c;
		}

		trap_R_AddPolyToScene( &poly );
	}
}
Esempio n. 24
0
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame on fast clients.

If "g_synchronousClients 1" is set, this will be called exactly
once for each server frame, which makes for smooth demo recording.
==============
*/
void ClientThink_real( gentity_t *ent ) {
	gclient_t	*client;
	pmove_t		pm;
	int			oldEventSequence;
	int			msec;
	int			i;
	usercmd_t	*ucmd;

	client = ent->client;

	// don't think if the client is not yet connected (and thus not yet spawned in)
	if (client->pers.connected != CON_CONNECTED) {
		return;
	}
	// mark the time, so the connection sprite can be removed
	ucmd = &ent->client->pers.cmd;

	// sanity check the command time to prevent speedup cheating
	if ( ucmd->serverTime > level.time + 200 ) {
		ucmd->serverTime = level.time + 200;
//		G_Printf("serverTime <<<<<\n" );
	}
	if ( ucmd->serverTime < level.time - 1000 ) {
		ucmd->serverTime = level.time - 1000;
//		G_Printf("serverTime >>>>>\n" );
	} 

	msec = ucmd->serverTime - client->ps.commandTime;
	// following others may result in bad times, but we still want
	// to check for follow toggles
	if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) {
		return;
	}
	if ( msec > 200 ) {
		msec = 200;
	}

	if ( pmove_msec.integer < 8 ) {
		trap_Cvar_Set("pmove_msec", "8");
	}
	else if (pmove_msec.integer > 33) {
		trap_Cvar_Set("pmove_msec", "33");
	}

	if ( pmove_fixed.integer || client->pers.pmoveFixed ) {
		ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
		//if (ucmd->serverTime - client->ps.commandTime <= 0)
		//	return;
	}

	//
	// check for exiting intermission
	//
	if ( level.intermissiontime ) {
		ClientIntermissionThink( client );
		return;
	}

	// spectators don't do much
	if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
		if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
			return;
		}
		SpectatorThink( ent, ucmd );
		return;
	}

	if (ent && ent->client && (ent->client->ps.eFlags & EF_INVULNERABLE))
	{
		if (ent->client->invulnerableTimer <= level.time)
		{
			ent->client->ps.eFlags &= ~EF_INVULNERABLE;
		}
	}

	// check for inactivity timer, but never drop the local client of a non-dedicated server
	if ( !ClientInactivityTimer( client ) ) {
		return;
	}

	// clear the rewards if time
	if ( level.time > client->rewardTime ) {
		client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
	}

	if ( client->noclip ) {
		client->ps.pm_type = PM_NOCLIP;
	} else if ( client->ps.eFlags & EF_DISINTEGRATION ) {
		client->ps.pm_type = PM_NOCLIP;
	} else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
		client->ps.pm_type = PM_DEAD;
	} else {
		if (client->ps.forceGripChangeMovetype)
		{
			client->ps.pm_type = client->ps.forceGripChangeMovetype;
		}
		else
		{
			client->ps.pm_type = PM_NORMAL;
		}
	}

	client->ps.gravity = g_gravity.value;

	// set speed
	client->ps.speed = g_speed.value;
	client->ps.basespeed = g_speed.value;

	if (ent->client->ps.duelInProgress)
	{
		gentity_t *duelAgainst = &g_entities[ent->client->ps.duelIndex];

		//Keep the time updated, so once this duel ends this player can't engage in a duel for another
		//10 seconds. This will give other people a chance to engage in duels in case this player wants
		//to engage again right after he's done fighting and someone else is waiting.
		ent->client->ps.fd.privateDuelTime = level.time + 10000;

		if (ent->client->ps.duelTime < level.time)
		{
			//Bring out the sabers
			if (ent->client->ps.weapon == WP_SABER && ent->client->ps.saberHolstered &&
				ent->client->ps.duelTime)
			{
				if (!saberOffSound || !saberOnSound)
				{
					saberOffSound = G_SoundIndex("sound/weapons/saber/saberoffquick.wav");
					saberOnSound = G_SoundIndex("sound/weapons/saber/saberon.wav");
				}

				ent->client->ps.saberHolstered = qfalse;
				G_Sound(ent, CHAN_AUTO, saberOnSound);

				G_AddEvent(ent, EV_PRIVATE_DUEL, 2);

				ent->client->ps.duelTime = 0;
			}

			if (duelAgainst && duelAgainst->client && duelAgainst->inuse &&
				duelAgainst->client->ps.weapon == WP_SABER && duelAgainst->client->ps.saberHolstered &&
				duelAgainst->client->ps.duelTime)
			{
				if (!saberOffSound || !saberOnSound)
				{
					saberOffSound = G_SoundIndex("sound/weapons/saber/saberoffquick.wav");
					saberOnSound = G_SoundIndex("sound/weapons/saber/saberon.wav");
				}

				duelAgainst->client->ps.saberHolstered = qfalse;
				G_Sound(duelAgainst, CHAN_AUTO, saberOnSound);

				G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 2);

				duelAgainst->client->ps.duelTime = 0;
			}
		}
		else
		{
			client->ps.speed = 0;
			client->ps.basespeed = 0;
			ucmd->forwardmove = 0;
			ucmd->rightmove = 0;
			ucmd->upmove = 0;
		}

		if (!duelAgainst || !duelAgainst->client || !duelAgainst->inuse ||
			duelAgainst->client->ps.duelIndex != ent->s.number)
		{
			ent->client->ps.duelInProgress = 0;
			G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
		}
		else if (duelAgainst->health < 1 || duelAgainst->client->ps.stats[STAT_HEALTH] < 1)
		{
			ent->client->ps.duelInProgress = 0;
			duelAgainst->client->ps.duelInProgress = 0;

			G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
			G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);

			//Winner gets full health.. providing he's still alive
			if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
			{
				if (ent->health < ent->client->ps.stats[STAT_MAX_HEALTH])
				{
					ent->client->ps.stats[STAT_HEALTH] = ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
				}

				if (g_spawnInvulnerability.integer)
				{
					ent->client->ps.eFlags |= EF_INVULNERABLE;
					ent->client->invulnerableTimer = level.time + g_spawnInvulnerability.integer;
				}
			}

			/*
			trap_SendServerCommand( ent-g_entities, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER")) );
			trap_SendServerCommand( duelAgainst-g_entities, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER")) );
			*/
			//Private duel announcements are now made globally because we only want one duel at a time.
			if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
			{
				trap_SendServerCommand( -1, va("cp \"%s %s %s!\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER"), duelAgainst->client->pers.netname) );
			}
			else
			{ //it was a draw, because we both managed to die in the same frame
				trap_SendServerCommand( -1, va("cp \"%s\n\"", G_GetStripEdString("SVINGAME", "PLDUELTIE")) );
			}
		}
		else
		{
			vec3_t vSub;
			float subLen = 0;

			VectorSubtract(ent->client->ps.origin, duelAgainst->client->ps.origin, vSub);
			subLen = VectorLength(vSub);

			if (subLen >= 1024)
			{
				ent->client->ps.duelInProgress = 0;
				duelAgainst->client->ps.duelInProgress = 0;

				G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
				G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);

				trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "PLDUELSTOP")) );
			}
		}
	}

	/*
	if ( client->ps.powerups[PW_HASTE] ) {
		client->ps.speed *= 1.3;
	}
	*/

	if (client->ps.usingATST && ent->health > 0)
	{ //we have special shot clip boxes as an ATST
		ent->r.contents |= CONTENTS_NOSHOT;
		ATST_ManageDamageBoxes(ent);
	}
	else
	{
		ent->r.contents &= ~CONTENTS_NOSHOT;
		client->damageBoxHandle_Head = 0;
		client->damageBoxHandle_RLeg = 0;
		client->damageBoxHandle_LLeg = 0;
	}

	//rww - moved this stuff into the pmove code so that it's predicted properly
	//BG_AdjustClientSpeed(&client->ps, &client->pers.cmd, level.time);

	// set up for pmove
	oldEventSequence = client->ps.eventSequence;

	memset (&pm, 0, sizeof(pm));

	if ( ent->flags & FL_FORCE_GESTURE ) {
		ent->flags &= ~FL_FORCE_GESTURE;
		ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
	}

	if (ent->client && ent->client->ps.fallingToDeath &&
		(level.time - FALL_FADE_TIME) > ent->client->ps.fallingToDeath)
	{ //die!
		player_die(ent, ent, ent, 100000, MOD_FALLING);
		respawn(ent);
		ent->client->ps.fallingToDeath = 0;

		G_MuteSound(ent->s.number, CHAN_VOICE); //stop screaming, because you are dead!
	}

	if (ent->client->ps.otherKillerTime > level.time &&
		ent->client->ps.groundEntityNum != ENTITYNUM_NONE &&
		ent->client->ps.otherKillerDebounceTime < level.time)
	{
		ent->client->ps.otherKillerTime = 0;
		ent->client->ps.otherKiller = ENTITYNUM_NONE;
	}
	else if (ent->client->ps.otherKillerTime > level.time &&
		ent->client->ps.groundEntityNum == ENTITYNUM_NONE)
	{
		if (ent->client->ps.otherKillerDebounceTime < (level.time + 100))
		{
			ent->client->ps.otherKillerDebounceTime = level.time + 100;
		}
	}

//	WP_ForcePowersUpdate( ent, msec, ucmd); //update any active force powers
//	WP_SaberPositionUpdate(ent, ucmd); //check the server-side saber point, do apprioriate server-side actions (effects are cs-only)

	if ((ent->client->pers.cmd.buttons & BUTTON_USE) && ent->client->ps.useDelay < level.time)
	{
		TryUse(ent);
		ent->client->ps.useDelay = level.time + 100;
	}

	pm.ps = &client->ps;
	pm.cmd = *ucmd;
	if ( pm.ps->pm_type == PM_DEAD ) {
		pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
	}
	else if ( ent->r.svFlags & SVF_BOT ) {
		pm.tracemask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP;
	}
	else {
		pm.tracemask = MASK_PLAYERSOLID;
	}
	pm.trace = trap_Trace;
	pm.pointcontents = trap_PointContents;
	pm.debugLevel = g_debugMove.integer;
	pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;

	pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
	pm.pmove_msec = pmove_msec.integer;

	pm.animations = bgGlobalAnimations;//NULL;

	pm.gametype = g_gametype.integer;

	VectorCopy( client->ps.origin, client->oldOrigin );

	if (level.intermissionQueued != 0 && g_singlePlayer.integer) {
		if ( level.time - level.intermissionQueued >= 1000  ) {
			pm.cmd.buttons = 0;
			pm.cmd.forwardmove = 0;
			pm.cmd.rightmove = 0;
			pm.cmd.upmove = 0;
			if ( level.time - level.intermissionQueued >= 2000 && level.time - level.intermissionQueued <= 2500 ) {
				trap_SendConsoleCommand( EXEC_APPEND, "centerview\n");
			}
			ent->client->ps.pm_type = PM_SPINTERMISSION;
		}
	}

	for ( i = 0 ; i < MAX_CLIENTS ; i++ )
	{
		if (g_entities[i].inuse && g_entities[i].client)
		{
			pm.bgClients[i] = &g_entities[i].client->ps;
		}
	}

	if (ent->client->ps.saberLockTime > level.time)
	{
		gentity_t *blockOpp = &g_entities[ent->client->ps.saberLockEnemy];

		if (blockOpp && blockOpp->inuse && blockOpp->client)
		{
			vec3_t lockDir, lockAng;

			//VectorClear( ent->client->ps.velocity );
			VectorSubtract( blockOpp->r.currentOrigin, ent->r.currentOrigin, lockDir );
			//lockAng[YAW] = vectoyaw( defDir );
			vectoangles(lockDir, lockAng);
			SetClientViewAngle( ent, lockAng );
		}

		if ( ( ent->client->buttons & BUTTON_ATTACK ) && ! ( ent->client->oldbuttons & BUTTON_ATTACK ) )
		{
			ent->client->ps.saberLockHits++;
		}
		if (ent->client->ps.saberLockHits > 2)
		{
			if (!ent->client->ps.saberLockAdvance)
			{
				ent->client->ps.saberLockHits -= 3;
			}
			ent->client->ps.saberLockAdvance = qtrue;
		}
	}
	else
	{
		ent->client->ps.saberLockFrame = 0;
		//check for taunt
		if ( (pm.cmd.generic_cmd == GENCMD_ENGAGE_DUEL) && (g_gametype.integer == GT_TOURNAMENT) )
		{//already in a duel, make it a taunt command
			pm.cmd.buttons |= BUTTON_GESTURE;
		}
	}

	Pmove (&pm);

	if (pm.checkDuelLoss)
	{
		if (pm.checkDuelLoss > 0 && pm.checkDuelLoss <= MAX_CLIENTS)
		{
			gentity_t *clientLost = &g_entities[pm.checkDuelLoss-1];

			if (clientLost && clientLost->inuse && clientLost->client && Q_irand(0, 40) > clientLost->health)
			{
				vec3_t attDir;
				VectorSubtract(ent->client->ps.origin, clientLost->client->ps.origin, attDir);
				VectorNormalize(attDir);

				VectorClear(clientLost->client->ps.velocity);
				clientLost->client->ps.forceHandExtend = HANDEXTEND_NONE;
				clientLost->client->ps.forceHandExtendTime = 0;

				gGAvoidDismember = 1;
				G_Damage(clientLost, ent, ent, attDir, clientLost->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_SABER);

				if (clientLost->health < 1)
				{
					gGAvoidDismember = 2;
					G_CheckForDismemberment(clientLost, clientLost->client->ps.origin, 999, (clientLost->client->ps.legsAnim&~ANIM_TOGGLEBIT));
				}

				gGAvoidDismember = 0;
			}
		}

		pm.checkDuelLoss = 0;
	}

	switch(pm.cmd.generic_cmd)
	{
	case 0:
		break;
	case GENCMD_SABERSWITCH:
		Cmd_ToggleSaber_f(ent);
		break;
	case GENCMD_ENGAGE_DUEL:
		if ( g_gametype.integer == GT_TOURNAMENT )
		{//already in a duel, made it a taunt command
		}
		else
		{
			Cmd_EngageDuel_f(ent);
		}
		break;
	case GENCMD_FORCE_HEAL:
		ForceHeal(ent);
		break;
	case GENCMD_FORCE_SPEED:
		ForceSpeed(ent, 0);
		break;
	case GENCMD_FORCE_THROW:
		ForceThrow(ent, qfalse);
		break;
	case GENCMD_FORCE_PULL:
		ForceThrow(ent, qtrue);
		break;
	case GENCMD_FORCE_DISTRACT:
		ForceTelepathy(ent);
		break;
	case GENCMD_FORCE_RAGE:
		ForceRage(ent);
		break;
	case GENCMD_FORCE_PROTECT:
		ForceProtect(ent);
		break;
	case GENCMD_FORCE_ABSORB:
		ForceAbsorb(ent);
		break;
	case GENCMD_FORCE_HEALOTHER:
		ForceTeamHeal(ent);
		break;
	case GENCMD_FORCE_FORCEPOWEROTHER:
		ForceTeamForceReplenish(ent);
		break;
	case GENCMD_FORCE_SEEING:
		ForceSeeing(ent);
		break;
	case GENCMD_USE_SEEKER:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SEEKER)) &&
			G_ItemUsable(&ent->client->ps, HI_SEEKER) )
		{
			ItemUse_Seeker(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SEEKER, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SEEKER);
		}
		break;
	case GENCMD_USE_FIELD:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SHIELD)) &&
			G_ItemUsable(&ent->client->ps, HI_SHIELD) )
		{
			ItemUse_Shield(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SHIELD, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SHIELD);
		}
		break;
	case GENCMD_USE_BACTA:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_MEDPAC)) &&
			G_ItemUsable(&ent->client->ps, HI_MEDPAC) )
		{
			ItemUse_MedPack(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_MEDPAC, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_MEDPAC);
		}
		break;
	case GENCMD_USE_ELECTROBINOCULARS:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
			G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
		{
			ItemUse_Binoculars(ent);
			if (ent->client->ps.zoomMode == 0)
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
			}
			else
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
			}
		}
		break;
	case GENCMD_ZOOM:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
			G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
		{
			ItemUse_Binoculars(ent);
			if (ent->client->ps.zoomMode == 0)
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
			}
			else
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
			}
		}
		break;
	case GENCMD_USE_SENTRY:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SENTRY_GUN)) &&
			G_ItemUsable(&ent->client->ps, HI_SENTRY_GUN) )
		{
			ItemUse_Sentry(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SENTRY_GUN, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SENTRY_GUN);
		}
		break;
	case GENCMD_SABERATTACKCYCLE:
		Cmd_SaberAttackCycle_f(ent);
		break;
	default:
		break;
	}

	// save results of pmove
	if ( ent->client->ps.eventSequence != oldEventSequence ) {
		ent->eventTime = level.time;
	}
	if (g_smoothClients.integer) {
		BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
	}
	else {
		BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
	}
	SendPendingPredictableEvents( &ent->client->ps );

	if ( !( ent->client->ps.eFlags & EF_FIRING ) ) {
		client->fireHeld = qfalse;		// for grapple
	}

	// use the snapped origin for linking so it matches client predicted versions
	VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );

	VectorCopy (pm.mins, ent->r.mins);
	VectorCopy (pm.maxs, ent->r.maxs);

	ent->waterlevel = pm.waterlevel;
	ent->watertype = pm.watertype;

	// execute client events
	ClientEvents( ent, oldEventSequence );

	if ( pm.useEvent )
	{
		//TODO: Use
//		TryUse( ent );
	}

	// link entity now, after any personal teleporters have been used
	trap_LinkEntity (ent);
	if ( !ent->client->noclip ) {
		G_TouchTriggers( ent );
	}

	// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
	VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );

	//test for solid areas in the AAS file
//	BotTestAAS(ent->r.currentOrigin);

	// touch other objects
	ClientImpacts( ent, &pm );

	// save results of triggers and client events
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime = level.time;
	}

	// swap and latch button actions
	client->oldbuttons = client->buttons;
	client->buttons = ucmd->buttons;
	client->latched_buttons |= client->buttons & ~client->oldbuttons;

	// Did we kick someone in our pmove sequence?
	if (client->ps.forceKickFlip)
	{
		gentity_t *faceKicked = &g_entities[client->ps.forceKickFlip-1];

		if (faceKicked && faceKicked->client && (!OnSameTeam(ent, faceKicked) || g_friendlyFire.integer) &&
			(!faceKicked->client->ps.duelInProgress || faceKicked->client->ps.duelIndex == ent->s.number) &&
			(!ent->client->ps.duelInProgress || ent->client->ps.duelIndex == faceKicked->s.number))
		{
			if ( faceKicked && faceKicked->client && faceKicked->health && faceKicked->takedamage )
			{//push them away and do pain
				vec3_t oppDir;
				int strength = (int)VectorNormalize2( client->ps.velocity, oppDir );

				strength *= 0.05;

				VectorScale( oppDir, -1, oppDir );

				G_Damage( faceKicked, ent, ent, oppDir, client->ps.origin, strength, DAMAGE_NO_ARMOR, MOD_MELEE );

				if ( faceKicked->client->ps.weapon != WP_SABER ||
					 faceKicked->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3 ||
					 (!BG_SaberInAttack(faceKicked->client->ps.saberMove) && !PM_SaberInStart(faceKicked->client->ps.saberMove) && !PM_SaberInReturn(faceKicked->client->ps.saberMove) && !PM_SaberInTransition(faceKicked->client->ps.saberMove)) )
				{
					if (faceKicked->health > 0 &&
						faceKicked->client->ps.stats[STAT_HEALTH] > 0 &&
						faceKicked->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
					{
						if (Q_irand(1, 10) <= 3)
						{ //only actually knock over sometimes, but always do velocity hit
							faceKicked->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
							faceKicked->client->ps.forceHandExtendTime = level.time + 1100;
							faceKicked->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
						}

						faceKicked->client->ps.otherKiller = ent->s.number;
						faceKicked->client->ps.otherKillerTime = level.time + 5000;
						faceKicked->client->ps.otherKillerDebounceTime = level.time + 100;

						faceKicked->client->ps.velocity[0] = oppDir[0]*(strength*40);
						faceKicked->client->ps.velocity[1] = oppDir[1]*(strength*40);
						faceKicked->client->ps.velocity[2] = 200;
					}
				}

				G_Sound( faceKicked, CHAN_AUTO, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) );
			}
		}

		client->ps.forceKickFlip = 0;
	}

	// check for respawning
	if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
		// wait for the attack button to be pressed
		if ( level.time > client->respawnTime && !gDoSlowMoDuel ) {
			// forcerespawn is to prevent users from waiting out powerups
			if ( g_forcerespawn.integer > 0 && 
				( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) {
				respawn( ent );
				return;
			}
		
			// pressing attack or use is the normal respawn method
			if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {
				respawn( ent );
			}
		}
		else if (gDoSlowMoDuel)
		{
			client->respawnTime = level.time + 1000;
		}
		return;
	}

	// perform once-a-second actions
	ClientTimerActions( ent, msec );

	G_UpdateClientBroadcasts ( ent );
}
Esempio n. 25
0
/*
=================
R_SetupEntityLightingGrid

=================
*/
static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
	vec3_t			lightOrigin;
	int				pos[3];
	int				i, j;
	float			frac[3];
	int				gridStep[3];
	vec3_t			direction;
	float			totalFactor;
	unsigned short	*startGridPos;

	
	if (r_fullbright->integer || tr.refdef.doFullbright )
	{
		ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[2] = 255.0;
		ent->directedLight[0] = ent->directedLight[1] = ent->directedLight[2] = 255.0;
		VectorCopy( tr.sunDirection, ent->lightDir );
		return;
	}

	if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
		// seperate lightOrigins are needed so an object that is
		// sinking into the ground can still be lit, and so
		// multi-part models can be lit identically
		VectorCopy( ent->e.lightingOrigin, lightOrigin );
	} else {
		VectorCopy( ent->e.origin, lightOrigin );
	}
#define ACCURATE_LIGHTGRID_SAMPLING 1
#if ACCURATE_LIGHTGRID_SAMPLING
	vec3_t	startLightOrigin;
	VectorCopy( lightOrigin, startLightOrigin );
#endif

	VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
	for ( i = 0 ; i < 3 ; i++ ) {
		float	v;

		v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
		pos[i] = floor( v );
		frac[i] = v - pos[i];
		if ( pos[i] < 0 ) {
			pos[i] = 0;
		} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
			pos[i] = tr.world->lightGridBounds[i] - 1;
		}
	}

	VectorClear( ent->ambientLight );
	VectorClear( ent->directedLight );
	VectorClear( direction );

	// trilerp the light value
	gridStep[0] = 1;
	gridStep[1] = tr.world->lightGridBounds[0];
	gridStep[2] = tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
	startGridPos = tr.world->lightGridArray	+ pos[0] * gridStep[0] 
					+ pos[1] * gridStep[1] 	+ pos[2] * gridStep[2];
#if ACCURATE_LIGHTGRID_SAMPLING
	vec3_t	startGridOrg;
	VectorCopy( tr.world->lightGridOrigin, startGridOrg );
	startGridOrg[0] += pos[0] * tr.world->lightGridSize[0];
	startGridOrg[1] += pos[1] * tr.world->lightGridSize[1];
	startGridOrg[2] += pos[2] * tr.world->lightGridSize[2];
#endif
	totalFactor = 0;
	for ( i = 0 ; i < 8 ; i++ ) {
		float			factor;
		mgrid_t			*data;
		unsigned short	*gridPos;
		int				lat, lng;
		vec3_t			normal;
#if ACCURATE_LIGHTGRID_SAMPLING
		vec3_t			gridOrg;
		VectorCopy( startGridOrg, gridOrg );
#endif

		factor = 1.0;
		gridPos = startGridPos;
		for ( j = 0 ; j < 3 ; j++ ) {
			if ( i & (1<<j) ) {
				factor *= frac[j];
				gridPos += gridStep[j];
#if ACCURATE_LIGHTGRID_SAMPLING
				gridOrg[j] += tr.world->lightGridSize[j];
#endif
			} else {
				factor *= (1.0 - frac[j]);
			}
		}

		if (gridPos >= tr.world->lightGridArray + tr.world->numGridArrayElements)
		{//we've gone off the array somehow
			continue;
		}
		data = tr.world->lightGridData + *gridPos;
		if ( data->styles[0] == LS_NONE ) 
		{
			continue;	// ignore samples in walls
		}

#if 0
		if ( !SV_inPVS( startLightOrigin, gridOrg ) )
		{
			continue;
		}
#endif

		totalFactor += factor;

		for(j=0;j<MAXLIGHTMAPS;j++)
		{
			if (data->styles[j] != LS_NONE)
			{
				const byte	style= data->styles[j];

				ent->ambientLight[0] += factor * data->ambientLight[j][0] * styleColors[style][0] / 255.0f;
				ent->ambientLight[1] += factor * data->ambientLight[j][1] * styleColors[style][1] / 255.0f;
				ent->ambientLight[2] += factor * data->ambientLight[j][2] * styleColors[style][2] / 255.0f;

				ent->directedLight[0] += factor * data->directLight[j][0] * styleColors[style][0] / 255.0f;
				ent->directedLight[1] += factor * data->directLight[j][1] * styleColors[style][1] / 255.0f;
				ent->directedLight[2] += factor * data->directLight[j][2] * styleColors[style][2] / 255.0f;
			}
			else
			{
				break;
			}
		}


		lat = data->latLong[1];
		lng = data->latLong[0];
		lat *= (FUNCTABLE_SIZE/256);
		lng *= (FUNCTABLE_SIZE/256);

		// decode X as cos( lat ) * sin( long )
		// decode Y as sin( lat ) * sin( long )
		// decode Z as cos( long )

		normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
		normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
		normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];

		VectorMA( direction, factor, normal, direction );

#if ACCURATE_LIGHTGRID_SAMPLING
		if ( r_debugLight->integer && ent->e.hModel == -1 )
		{
			//draw 	
			refEntity_t refEnt;
			refEnt.hModel = 0;
			refEnt.ghoul2 = NULL;
			refEnt.renderfx = 0;
			VectorCopy( gridOrg, refEnt.origin );
			vectoangles( normal, refEnt.angles );
			AnglesToAxis( refEnt.angles, refEnt.axis );
			refEnt.reType = RT_MODEL;
			RE_AddRefEntityToScene( &refEnt );

			refEnt.renderfx = RF_DEPTHHACK;
			refEnt.reType = RT_SPRITE;
			refEnt.customShader = RE_RegisterShader( "gfx/misc/debugAmbient" );
			refEnt.shaderRGBA[0] = data->ambientLight[0][0];
			refEnt.shaderRGBA[1] = data->ambientLight[0][1];
			refEnt.shaderRGBA[2] = data->ambientLight[0][2];
			refEnt.shaderRGBA[3] = 255;
			refEnt.radius = factor*50+2.0f; // maybe always give it a minimum size?
			refEnt.rotation = 0;			// don't let the sprite wobble around
			RE_AddRefEntityToScene( &refEnt );

			refEnt.reType = RT_LINE;
			refEnt.customShader = RE_RegisterShader( "gfx/misc/debugArrow" );
			refEnt.shaderRGBA[0] = data->directLight[0][0];
			refEnt.shaderRGBA[1] = data->directLight[0][1];
			refEnt.shaderRGBA[2] = data->directLight[0][2];
			refEnt.shaderRGBA[3] = 255;
			VectorCopy( refEnt.origin, refEnt.oldorigin );
			VectorMA( gridOrg, (factor*-255) - 2.0f, normal, refEnt.origin ); // maybe always give it a minimum length
			refEnt.radius = 1.5f;
			RE_AddRefEntityToScene( &refEnt );
		}
#endif
	}

	if ( totalFactor > 0 && totalFactor < 0.99 ) 
	{
		totalFactor = 1.0 / totalFactor;
		VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
		VectorScale( ent->directedLight, totalFactor, ent->directedLight );
	}

	VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
	VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );

	VectorNormalize2( direction, ent->lightDir );
}
Esempio n. 26
0
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, 
				   float orientation, float red, float green, float blue, float alpha,
				   qboolean alphaFade, float radius, qboolean temporary )
#endif
{
	vec3_t			axis[3];
	float			texCoordScale;
	vec3_t			originalPoints[4];
	byte			colors[4];
	int				i, j;
	int				numFragments;
	markFragment_t	markFragments[MAX_MARK_FRAGMENTS], *mf;
	vec3_t			markPoints[MAX_MARK_POINTS];
	vec3_t			projection;
#ifdef TA_WEAPSYS
	qboolean addedMark = qfalse;
#endif

	if ( !cg_addMarks.integer ) {
#ifdef TA_WEAPSYS
		return qfalse;
#else
		return;
#endif
	}

	if ( radius <= 0 ) {
		CG_Error( "CG_ImpactMark called with <= 0 radius" );
	}

#ifndef IOQ3ZTM
	//if ( markTotal >= MAX_MARK_POLYS ) {
	//	return;
	//}
#endif

	// create the texture axis
	VectorNormalize2( dir, axis[0] );
	PerpendicularVector( axis[1], axis[0] );
	RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
	CrossProduct( axis[0], axis[2], axis[1] );

	texCoordScale = 0.5 * 1.0 / radius;

	// create the full polygon
	for ( i = 0 ; i < 3 ; i++ ) {
		originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
		originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
		originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
		originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
	}

	// get the fragments
	VectorScale( dir, -20, projection );
	numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
					projection, MAX_MARK_POINTS, markPoints[0],
					MAX_MARK_FRAGMENTS, markFragments );

	colors[0] = red * 255;
	colors[1] = green * 255;
	colors[2] = blue * 255;
	colors[3] = alpha * 255;

	for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
		polyVert_t	*v;
		polyVert_t	verts[MAX_VERTS_ON_POLY];
		markPoly_t	*mark;
		vec3_t		delta;
		vec3_t		localOrigin;

		// create the texture axis
		VectorNormalize2( mf->projectionDir, axis[0] );
		VectorScale( axis[0], -1, axis[0] ); // ZTM: the dir was scaled to -20 before giving to renderer, turn it back around. :S
		PerpendicularVector( axis[1], axis[0] );
		RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
		CrossProduct( axis[0], axis[2], axis[1] );

		if ( mf->bmodelNum ) {
			// ZTM: TODO?: compensate for scale in the axes if necessary? see R_RotateForEntity
			// ZTM: FIXME: cgame should be able to get origin and axis from entity !
			VectorSubtract( origin, mf->bmodelOrigin, delta );
			localOrigin[0] = DotProduct( delta, mf->bmodelAxis[0] );
			localOrigin[1] = DotProduct( delta, mf->bmodelAxis[1] );
			localOrigin[2] = DotProduct( delta, mf->bmodelAxis[2] );
		} else {
			VectorCopy( origin, localOrigin );
		}

		// we have an upper limit on the complexity of polygons
		// that we store persistantly
		if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
			mf->numPoints = MAX_VERTS_ON_POLY;
		}
		for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
			VectorCopy( markPoints[mf->firstPoint + j], v->xyz );

			VectorSubtract( v->xyz, localOrigin, delta );
			v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
			v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
			*(int *)v->modulate = *(int *)colors;
		}

		// if it is a temporary (shadow) mark, add it immediately and forget about it
		if ( temporary ) {
			trap_R_AddPolyToScene( markShader, mf->numPoints, verts, mf->bmodelNum, 0 );
			continue;
		}

		// otherwise save it persistantly
		mark = CG_AllocMark();
		mark->bmodelNum = mf->bmodelNum;
		mark->time = cg.time;
		mark->alphaFade = alphaFade;
		mark->markShader = markShader;
		mark->numVerts = mf->numPoints;
		mark->color[0] = red;
		mark->color[1] = green;
		mark->color[2] = blue;
		mark->color[3] = alpha;
		memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
#ifndef IOQ3ZTM
		markTotal++;
#endif
#ifdef TA_WEAPSYS
		addedMark = qtrue;
#endif
	}
#ifdef TA_WEAPSYS
	return addedMark;
#endif
}
Esempio n. 27
0
/*
=================
R_SetupEntityLightingGrid
=================
*/
static void R_SetupEntityLightingGrid(trRefEntity_t *ent)
{
	vec3_t lightOrigin;
	int    pos[3];
	int    i, j;
	byte   *gridData;
	float  frac[3];
	int    gridStep[3];
	vec3_t direction;
	float  totalFactor;
	float  factor;
	byte   *data;
	int    lat, lng;
	vec3_t normal;
	float  v;

	if (ent->e.renderfx & RF_LIGHTING_ORIGIN)
	{
		// seperate lightOrigins are needed so an object that is
		// sinking into the ground can still be lit, and so
		// multi-part models can be lit identically
		VectorCopy(ent->e.lightingOrigin, lightOrigin);
	}
	else
	{
		VectorCopy(ent->e.origin, lightOrigin);
	}

	VectorSubtract(lightOrigin, tr.world->lightGridOrigin, lightOrigin);
	for (i = 0 ; i < 3 ; i++)
	{
		v       = lightOrigin[i] * tr.world->lightGridInverseSize[i];
		pos[i]  = floor(v);
		frac[i] = v - pos[i];
		if (pos[i] < 0)
		{
			pos[i] = 0;
		}
		else if (pos[i] > tr.world->lightGridBounds[i] - 1)
		{
			pos[i] = tr.world->lightGridBounds[i] - 1;
		}
	}

	VectorClear(ent->ambientLight);
	VectorClear(ent->directedLight);
	VectorClear(direction);

	assert(tr.world->lightGridData);   // bk010103 - NULL with -nolight maps

	// trilerp the light value
	gridStep[0] = 8;
	gridStep[1] = 8 * tr.world->lightGridBounds[0];
	gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
	gridData    = tr.world->lightGridData + pos[0] * gridStep[0]
	              + pos[1] * gridStep[1] + pos[2] * gridStep[2];

	totalFactor = 0;
	for (i = 0 ; i < 8 ; i++)
	{
		factor = 1.0;
		data   = gridData;
		for (j = 0 ; j < 3 ; j++)
		{
			if (i & (1 << j))
			{
				factor *= frac[j];
				data   += gridStep[j];
			}
			else
			{
				factor *= (1.0f - frac[j]);
			}
		}

		if (!(data[0] + data[1] + data[2]))
		{
			continue;   // ignore samples in walls
		}
		totalFactor += factor;

		ent->ambientLight[0] += factor * data[0];
		ent->ambientLight[1] += factor * data[1];
		ent->ambientLight[2] += factor * data[2];

		ent->directedLight[0] += factor * data[3];
		ent->directedLight[1] += factor * data[4];
		ent->directedLight[2] += factor * data[5];

		lat  = data[7];
		lng  = data[6];
		lat *= (FUNCTABLE_SIZE / 256);
		lng *= (FUNCTABLE_SIZE / 256);

		// decode X as cos( lat ) * sin( long )
		// decode Y as sin( lat ) * sin( long )
		// decode Z as cos( long )

		normal[0] = tr.sinTable[(lat + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK] * tr.sinTable[lng];
		normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
		normal[2] = tr.sinTable[(lng + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK];

		VectorMA(direction, factor, normal, direction);

		// test code
		//%	if( strstr( tr.models[ ent->e.hModel ]->name, ".mdm" ) && i == 0 )
		//%		ri.Printf( PRINT_ALL, "lat: %3d lng: %3d dir: %2.3f %2.3f %2.3f\n",
		//%			data[ 7 ], data[ 8 ], normal[ 0 ], normal[ 1 ], normal[ 2 ] );
	}

	if (totalFactor > 0 && totalFactor < 0.99)
	{
		totalFactor = 1.0f / totalFactor;
		VectorScale(ent->ambientLight, totalFactor, ent->ambientLight);
		VectorScale(ent->directedLight, totalFactor, ent->directedLight);
	}

	VectorScale(ent->ambientLight, r_ambientScale->value, ent->ambientLight);
	VectorScale(ent->directedLight, r_directedScale->value, ent->directedLight);

	// cheats?  check for single player?
	if (tr.lightGridMulDirected)
	{
		VectorScale(ent->directedLight, tr.lightGridMulDirected, ent->directedLight);
	}
	if (tr.lightGridMulAmbient)
	{
		VectorScale(ent->ambientLight, tr.lightGridMulAmbient, ent->ambientLight);
	}

	VectorNormalize2(direction, ent->lightDir);

	// debug hack
	//%	VectorSubtract( vec3_origin, direction, ent->lightDir );
}
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, 
				   float orientation, float red, float green, float blue, float alpha,
				   qboolean alphaFade, float radius, qboolean temporary ) {
	vec3_t			axis[3];
	float			texCoordScale;
	vec3_t			originalPoints[4];
	byte			colors[4];
	int				i, j;
	int				numFragments;
	markFragment_t	markFragments[MAX_MARK_FRAGMENTS], *mf;
	vec3_t			markPoints[MAX_MARK_POINTS];
	vec3_t			projection;
	markPoly_t		*mp, *next;
	vec3_t			delta;

	if ( !cg_addMarks.integer ) {
		return;
	}

	if ( radius <= 0 ) {
		CG_Error( "CG_ImpactMark called with <= 0 radius" );
	}

	//if ( markTotal >= MAX_MARK_POLYS ) {
	//	return;
	//}

	// HERBY: Bubble G overdraw fix
	mp = cg_activeMarkPolys.nextMark;
	for ( ; mp != &cg_activeMarkPolys; mp = next ) {
		next = mp->nextMark;
		if(temporary) break; // keep all marks if the new one is just the shadow
		if(mp->markShader == cgs.media.SchaumShader) continue;//die slick-ents einfach übergehen
		VectorSubtract( mp->origin, origin, delta );
		if ( radius <= mp->radius + 4 && VectorLength( delta ) < ( radius + mp->radius ) * MIN_MARK_DISTANCE ) {
			CG_FreeMarkPoly( mp );
		}
	}	

	// create the texture axis
	VectorNormalize2( dir, axis[0] );
	PerpendicularVector( axis[1], axis[0] );
	RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
	CrossProduct( axis[0], axis[2], axis[1] );

	texCoordScale = 0.5 * 1.0 / radius;

	// create the full polygon
	for ( i = 0 ; i < 3 ; ++i ) {
		originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
		originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
		originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
		originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
	}

	// get the fragments
	VectorScale( dir, -20, projection );
	numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
					projection, MAX_MARK_POINTS, markPoints[0],
					MAX_MARK_FRAGMENTS, markFragments );

	if(!numFragments && markShader == cgs.media.SchaumShader)
	{
		numFragments = 1;
		markFragments->firstPoint = 0;
		markFragments->numPoints = 4;
		for(i=0;i<4;++i)
			VectorCopy(originalPoints[i],markPoints[i]);
	}

	colors[0] = red * 255;
	colors[1] = green * 255;
	colors[2] = blue * 255;
	colors[3] = alpha * 255;

	for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
		polyVert_t	*v;
		polyVert_t	verts[MAX_VERTS_ON_POLY];
		markPoly_t	*mark;

		// we have an upper limit on the complexity of polygons
		// that we store persistantly
		if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
			mf->numPoints = MAX_VERTS_ON_POLY;
		}
		for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
			vec3_t		delta;

			VectorCopy( markPoints[mf->firstPoint + j], v->xyz );

			VectorSubtract( v->xyz, origin, delta );
			v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
			v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
			*(int *)v->modulate = *(int *)colors;
		}

		// if it is a temporary (shadow) mark, add it immediately and forget about it
		if ( temporary ) {
			trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
			continue;
		}

		// otherwise save it persistantly
		mark = CG_AllocMark();
		mark->time = cg.time;
		mark->alphaFade = alphaFade;
		mark->markShader = markShader;
		mark->poly.numVerts = mf->numPoints;
		mark->color[0] = red;
		mark->color[1] = green;
		mark->color[2] = blue;
		mark->color[3] = alpha;
		mark->radius = radius;
		VectorCopy( origin, mark->origin );
		memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
		markTotal++;
	}
}
Esempio n. 29
0
int R_MarkFragments( int numPoints, const vec3_t* points, const vec3_t projection,
	int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t* fragmentBuffer ) {
	//increment view count for double check prevention
	tr.viewCount++;

	vec3_t projectionDir;
	VectorNormalize2( projection, projectionDir );

	// find all the brushes that are to be considered
	vec3_t mins, maxs;
	ClearBounds( mins, maxs );
	for ( int i = 0; i < numPoints; i++ ) {
		AddPointToBounds( points[ i ], mins, maxs );
		vec3_t temp;
		VectorAdd( points[ i ], projection, temp );
		AddPointToBounds( temp, mins, maxs );
		// make sure we get all the leafs (also the one(s) in front of the hit surface)
		VectorMA( points[ i ], -20, projectionDir, temp );
		AddPointToBounds( temp, mins, maxs );
	}

	if ( numPoints > MAX_VERTS_ON_POLY ) {
		numPoints = MAX_VERTS_ON_POLY;
	}
	// create the bounding planes for the to be projected polygon
	vec3_t normals[ MAX_VERTS_ON_POLY + 2 ];
	float dists[ MAX_VERTS_ON_POLY + 2 ];
	for ( int i = 0; i < numPoints; i++ ) {
		vec3_t v1, v2;
		VectorSubtract( points[ ( i + 1 ) % numPoints ], points[ i ], v1 );
		VectorAdd( points[ i ], projection, v2 );
		VectorSubtract( points[ i ], v2, v2 );
		CrossProduct( v1, v2, normals[ i ] );
		VectorNormalizeFast( normals[ i ] );
		dists[ i ] = DotProduct( normals[ i ], points[ i ] );
	}

	// add near and far clipping planes for projection
	VectorCopy( projectionDir, normals[ numPoints ] );
	dists[ numPoints ] = DotProduct( normals[ numPoints ], points[ 0 ] ) - 32;
	VectorCopy( projectionDir, normals[ numPoints + 1 ] );
	VectorInverse( normals[ numPoints + 1 ] );
	dists[ numPoints + 1 ] = DotProduct( normals[ numPoints + 1 ], points[ 0 ] ) - 20;
	int numPlanes = numPoints + 2;

	int numsurfaces = 0;
	idWorldSurface* surfaces[ 64 ];
	R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir );
	//assert(numsurfaces <= 64);
	//assert(numsurfaces != 64);

	int returnedPoints = 0;
	int returnedFragments = 0;

	for ( int i = 0; i < numsurfaces; i++ ) {
		surfaces[ i ]->MarkFragments( projectionDir,
				numPlanes, normals, dists,
				maxPoints, pointBuffer,
				maxFragments, fragmentBuffer,
				&returnedPoints, &returnedFragments, mins, maxs );
		if ( returnedFragments == maxFragments ) {
			break;	// not enough space for more fragments
		}
	}
	return returnedFragments;
}
Esempio n. 30
0
//	generates a texture projection matrix for a triangle
// returns false if a texture matrix cannot be created
static bool MakeTextureMatrix( vec4_t texMat[ 2 ], vec4_t projection, decalVert_t* a, decalVert_t* b, decalVert_t* c ) {
	//	project triangle onto plane of projection
	dvec3_t pa, pb, pc;
	double d = DotProduct( a->xyz, projection ) - projection[ 3 ];
	VectorMA( a->xyz, -d, projection, pa );
	d = DotProduct( b->xyz, projection ) - projection[ 3 ];
	VectorMA( b->xyz, -d, projection, pb );
	d = DotProduct( c->xyz, projection ) - projection[ 3 ];
	VectorMA( c->xyz, -d, projection, pc );

	//	calculate barycentric basis for the triangle
	double bb = ( b->st[ 0 ] - a->st[ 0 ] ) * ( c->st[ 1 ] - a->st[ 1 ] ) - ( c->st[ 0 ] - a->st[ 0 ] ) * ( b->st[ 1 ] - a->st[ 1 ] );
	if ( fabs( bb ) < 0.00000001f ) {
		return false;
	}

	//	calculate texture origin
	double s = 0.0f;
	double t = 0.0f;
	dvec3_t bary;
	bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
	bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
	bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;

	dvec3_t origin;
	origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
	origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
	origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];

	//	calculate s vector
	s = 1.0f;
	t = 0.0f;
	bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
	bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
	bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;

	dvec3_t xyz;
	xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
	xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
	xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];

	vec3_t vecs[ 3 ];
	VectorSubtract( xyz, origin, vecs[ 0 ] );

	//	calculate t vector
	s = 0.0f;
	t = 1.0f;
	bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
	bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
	bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;

	xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
	xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
	xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];

	VectorSubtract( xyz, origin, vecs[ 1 ] );

	//	calcuate r vector
	VectorScale( projection, -1.0f, vecs[ 2 ] );

	//	calculate transform axis
	vec3_t axis[ 3 ];
	vec3_t lengths;
	for ( int i = 0; i < 3; i++ ) {
		lengths[ i ] = VectorNormalize2( vecs[ i ], axis[ i ] );
	}

	for ( int i = 0; i < 2; i++ ) {
		for ( int j = 0; j < 3; j++ ) {
			texMat[ i ][ j ] = lengths[ i ] > 0.0f ? ( axis[ i ][ j ] / lengths[ i ] ) : 0.0f;
		}
	}
	texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( pa, texMat[ 0 ] );
	texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( pa, texMat[ 1 ] );

	return true;
}