Пример #1
0
void
MOD_TraceLine (hull_t *hull, int num,
			   const vec3_t start_point, const vec3_t end_point,
			   trace_t *trace)
{
	trace->fraction = 1;
	trace->allsolid = true;
	SV_RecursiveHullCheck (hull, num, 0, 1, start_point, end_point, trace);
}
Пример #2
0
/*
==============
TraceLine

TODO: impact on bmodels, monsters
==============
*/
void TraceLine (vec3_t start, vec3_t end, vec3_t impact)
{
	trace_t	trace;

	memset (&trace, 0, sizeof(trace));
	SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);

	VectorCopy (trace.endpos, impact);
}
Пример #3
0
static float pfnTraceModel( physent_t *pe, float *start, float *end, trace_t *trace )
{
	int	old_usehull;
	vec3_t	start_l, end_l;
	vec3_t	offset, temp;
	qboolean	rotated;
	matrix4x4	matrix;
	hull_t	*hull;

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

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

	clgame.pmove->usehull = old_usehull;

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

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

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

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

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

	return trace->fraction;
}
Пример #4
0
/*
=================
TraceLineN
=================
*/
qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal)
{
	trace_t	trace;

	memset (&trace, 0, sizeof(trace));
	if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace))
	{
		if (trace.fraction < 1)
		{
			VectorCopy (trace.endpos, impact);
			if (normal)
				VectorCopy (trace.plane.normal, normal);

			return true;
		}
	}

	return false;
}
Пример #5
0
/*
=================
CL_UpdateTEnts
=================
*/
void CL_UpdateTEnts (void)
{
	int			i;
	beam_t		*b;
	vec3_t		dist, org, beamstart;
	float		d;
	entity_t	*ent;
	float		yaw, pitch;
	float		forward;

	int			j;
	vec3_t		beamend;
//	qboolean	sparks = false;

	num_temp_entities = 0;

// update lightning
	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
	{
		if (!b->model || b->endtime < cl.time)
			continue;

		// if coming from the player, update the start position
		if (b->entity == cl.viewentity)
		{
			VectorCopy (cl_entities[cl.viewentity].origin, b->start);

			b->start[2] += cl.crouch + bound(-7, scr_ofsy.value, 4);
			b->start[2] += bound(0, cl_lightning_zadjust.value, 20);//progs.dat aims from 20 for traceline

			if (cl_truelightning.value)
			{
				vec3_t	forward, v, org, ang;
				float	f, delta;
				trace_t	trace;

				f = fmax(0, fmin(1, cl_truelightning.value));

				VectorSubtract (playerbeam_end, cl_entities[cl.viewentity].origin, v);
				//v[2] -= 22;		// adjust for view height
				v[2] -= cl.crouch; //
				v[2] -= bound(0, cl_lightning_zadjust.value, 20);

				vectoangles (v, ang);

				// lerp pitch
				ang[0] = -ang[0];
				if (ang[0] < -180)
					ang[0] += 360;
				ang[0] += (cl.viewangles[0] - ang[0]) * f;

				// lerp yaw
				delta = cl.viewangles[1] - ang[1];
				if (delta > 180)
					delta -= 360;
				if (delta < -180)
					delta += 360;
				ang[1] += delta * f;
				ang[2] = 0;

				AngleVectors (ang, forward, NULLVEC, NULLVEC);
				VectorScale(forward, 600, forward);
				VectorCopy(cl_entities[cl.viewentity].origin, org);
				org[2] += bound(0, cl_lightning_zadjust.value, 20);//progs.dat aims from 20 for teaceline
				VectorAdd(org, forward, b->end);

				memset (&trace, 0, sizeof(trace_t));
				if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, org, b->end, &trace))
					VectorCopy(trace.endpos, b->end);
			}
		}

/*
	// if coming from the player, update the start position
		if (b->entity == cl.viewentity)
		{
			VectorCopy (cl_entities[cl.viewentity].origin, b->start);
		}
*/
	// calculate pitch and yaw
		VectorSubtract (b->end, b->start, dist);

		if (dist[1] == 0 && dist[0] == 0)
		{
			yaw = 0;
			if (dist[2] > 0)
				pitch = 90;
			else
				pitch = 270;
		}
		else
		{
			yaw = (int) (atan2f(dist[1], dist[0]) * 180 / M_PI);
			if (yaw < 0)
				yaw += 360;
	
			forward = sqrtf (dist[0]*dist[0] + dist[1]*dist[1]);
			pitch = (int) (atan2f(dist[2], forward) * 180 / M_PI);
			if (pitch < 0)
				pitch += 360;
		}
        // add new entities for the lightning
		VectorCopy(b->start, org);
		VectorCopy(b->start, beamstart);
		d = VectorNormalize (dist);
		VectorScale (dist, 30, dist);

		if (key_dest == key_game)
		{
			for ( ; d > 0 ; d -= 30)
			{
				if ((qmb_initialized && r_part_lightning.value) && (!cl.paused))
				{
					VectorAdd(org, dist, beamend);
					for (j=0 ; j<3 ; j++)
						beamend[j] += ((rand()%10)-5);
					QMB_LightningBeam (beamstart, beamend);
					//if ((r_glowlg.value) && (r_dynamic.value))
					//	CL_NewDlight (i, beamstart, 100, 0.1, lt_blue);
					VectorCopy(beamend, beamstart);
				}
				else
				{
					if (!(ent = CL_NewTempEntity()))
						return;
					VectorCopy(org, ent->origin);
					ent->model = b->model;
					ent->angles[0] = pitch;
					ent->angles[1] = yaw;
					ent->angles[2] = rand() % 360;
				}
				VectorAdd(org, dist, org);
			}
		}
/*
	// add new entities for the lightning
		VectorCopy (b->start, org);
		d = VectorNormalize(dist);
     	while (d > 0)
		{
			ent = CL_NewTempEntity ();
			if (!ent)
				return;
			VectorCopy (org, ent->origin);
			ent->model = b->model;
			ent->angles[0] = pitch;
			ent->angles[1] = yaw;
			ent->angles[2] = rand()%360;

			for (i=0 ; i<3 ; i++)
				org[i] += dist[i]*30;
			d -= 30;
		}
*/
	}
	
}
Пример #6
0
float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal)
{
	trace_t	trace;
	extern cvar_t env_engine;
	int	x;
	model_t      *mod;
	float		shortest;
	vec3_t		newstart, newend;

	memset (&trace, 0, sizeof(trace));
	VectorCopy (end, trace.endpos);
	trace.fraction = 1;
	trace.startsolid = true;
	
//	if (sv.active)
//		SV_RecursiveHullCheck (sv.worldmodel->hulls, 0, 0, 1, start, end, &trace);
//	else
	if (cl.worldmodel)
		SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);

	VectorCopy (trace.endpos, impact);
	VectorCopy (trace.plane.normal, normal);
	shortest = trace.fraction;	
	
	VectorCopy (end, trace.endpos);
	trace.fraction = 1;
	trace.startsolid = true;

	for (x = 0; x < traceline_entities; x++) 
	{ 
		mod = traceline_entity[x]->model; 

		if (mod->type != mod_brush) continue; 

		if (mod->name[0] != '*') continue; 

		// set up start point 
		// offset the start [0] and [1] points by entity origin to do func_train bmodels 
		// this is positioned above the model to account for moving bmodels (note the "-" in [2]) 
		newstart[0] = start[0] + cl_visedicts[x]->origin[0]; 
		newstart[1] = start[1] + cl_visedicts[x]->origin[1]; 
		newstart[2] = start[2] + cl_visedicts[x]->origin[2]; 

		// set up end point 
		newend[0] = end[0] + cl_visedicts[x]->origin[0]; 
		newend[1] = end[1] + cl_visedicts[x]->origin[1]; 
		newend[2] = end[2] + cl_visedicts[x]->origin[2]; 

		// reset trace
		memset (&trace, 0, sizeof(trace));
		VectorCopy (end, trace.endpos);
		trace.fraction = 1;
		trace.startsolid = true;

//		r = RecursiveLightPoint (mod->nodes + mod->hulls[0].firstclipnode, start, end); 
		SV_RecursiveHullCheck (mod->hulls, mod->hulls[0].firstclipnode, 0, 1, newstart, newend, &trace);

		// check for shortest path 
		if (trace.fraction < shortest) 
		{ 
			shortest = trace.fraction;
			VectorCopy (trace.endpos, impact);
			VectorSubtract(trace.endpos, cl_visedicts[x]->origin, trace.endpos);
			VectorCopy (trace.plane.normal, normal);
		} 

		VectorCopy (end, trace.endpos);
		trace.fraction = 1;
		trace.startsolid = true;
	} 

	return shortest;
}
Пример #7
0
/* DESCRIPTION: SV_ClipMoveToEntity/SV_SingleClipMoveToEntity
// LOCATION: world.c
// PATH: Mostly in this file.
//
// SV_ClipMoveToEntity is a proxy (and only access point) for the next one.
//
// The function seems to be related to collision detection.
*/
void SV_SingleClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t * Outgoing_Trace) {

   vec3_t var_c;
   vec3_t var_18;
   vec3_t var_24;
   hull_t * var_28;
//   int var_2c;
   int var_30;
   int var_34;
   int var_38;

   vec3_t forward;
   vec3_t right;
   vec3_t up;
   vec3_t var_68;
   int var_6c;
   trace_t var_a4;
   vec3_t var_bc;
   vec3_t var_c8;
   vec3_t var_d4;

   Q_memset(Outgoing_Trace, 0, sizeof(trace_t));

   Outgoing_Trace->fraction = 1.0;
   Outgoing_Trace->allsolid = 1;

   Outgoing_Trace->endpos[0] = end[0];
   Outgoing_Trace->endpos[1] = end[1];
   Outgoing_Trace->endpos[2] = end[2];

   if(global_sv.models[ent->v.modelindex]->modeltype == 3) {
      //taken: 1616, -528, 127.97 endpos

      var_28 = SV_HullForStudioModel(ent, mins, maxs, var_c, &var_30);
   }
   else {
      var_28 = SV_HullForEntity(ent, mins, maxs, var_c);
      var_30 = 1; //if model?
   }

   VectorSubtract(start, var_c, var_18);
   VectorSubtract(end, var_c, var_24);

   if((ent->v.solid != SOLID_BSP) ||
      (ent->v.angles[0] == 0 && ent->v.angles[1] == 0 && ent->v.angles[2] == 0)) {

      //taken
      var_38 = 0; //rotated prob
   }
   else { var_38 = 1; }

   if(var_38) { //This is another function in QW.

      AngleVectors(ent->v.angles, forward, right, up); //v.angles is def +58.

      VectorCopy(var_18, var_68);

      var_18[0] = DotProduct(var_68, forward);
      var_18[1] = -DotProduct(var_68, right);
      var_18[2] = DotProduct(var_68, up);

      VectorCopy(var_24, var_68);

      var_24[0] = DotProduct(var_68, forward);
      var_24[1] = -DotProduct(var_68, right);
      var_24[2] = DotProduct(var_68, up);
   } //Curiously enough, I'm taking linear algebra right now.  I hate it.

   //= 20
   if(var_30 == 1) {
      SV_RecursiveHullCheck(var_28, var_28->firstclipnode, 0, 1.0, var_18, var_24, Outgoing_Trace);
   }
   else {
      for(var_6c = 0, var_34 = 0; var_34 < var_30; var_34++) {

         Q_memset(&var_a4, 0, sizeof(trace_t));
         var_a4.fraction = 1.0;
         var_a4.allsolid = 1;
         VectorCopy(end, var_a4.endpos);

         SV_RecursiveHullCheck(&(var_28[var_34]), var_28[var_34].firstclipnode, 0, 1.0, var_18, var_24, &var_a4);

         if(var_34 != 0 && var_a4.startsolid == 0 && var_a4.allsolid == 0 &&
            var_a4.fraction > Outgoing_Trace->fraction) { continue; }

         if(Outgoing_Trace->startsolid == 0) {
            Q_memcpy(Outgoing_Trace, &var_a4, sizeof(trace_t));
         }
         else {
            Q_memcpy(Outgoing_Trace, &var_a4, sizeof(trace_t)); //Probably could be a bit more efficient here.
            Outgoing_Trace->startsolid = 1;
         }
         var_6c = var_34;
      }
      Outgoing_Trace->hitgroup = SV_HitgroupForStudioHull(var_6c);
   }

   if(Outgoing_Trace->fraction != 1.0) {
      if(var_38 != 0) {

         AngleVectorsTranspose(ent->v.angles, var_68, var_bc, var_c8);

         VectorCopy(Outgoing_Trace->plane.normal, var_d4);
         Outgoing_Trace->plane.normal[0] = DotProduct(var_d4, var_68);
         Outgoing_Trace->plane.normal[1] = -DotProduct(var_d4, var_bc);
         Outgoing_Trace->plane.normal[2] = DotProduct(var_d4, var_c8);
      }
      //Scaling, clearly.
      Outgoing_Trace->endpos[0] = start[0] + (Outgoing_Trace->fraction * (end[0] - start[0]));
      Outgoing_Trace->endpos[1] = start[1] + (Outgoing_Trace->fraction * (end[1] - start[1]));
      Outgoing_Trace->endpos[2] = start[2] + (Outgoing_Trace->fraction * (end[2] - start[2]));
   }
   if(Outgoing_Trace->fraction < 1.0 || Outgoing_Trace->startsolid != 0) {
      Outgoing_Trace->pHit = ent;
   }
}
Пример #8
0
static qboolean
SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, const vec3_t p1, const vec3_t p2, trace_t *trace)
{
	mclipnode_t	*node;
	mplane_t	*plane;
	float		t1, t2;
	float		frac;
	int			i;
	vec3_t		mid;
	int			side;
	float		midf;

// check for empty
	if (num < 0)
	{
		if (num != CONTENTS_SOLID)
		{
			trace->allsolid = false;
			if (num == CONTENTS_EMPTY)
				trace->inopen = true;
			else
				trace->inwater = true;
		}
		else
			trace->startsolid = true;
		return true;		// empty
	}

	if (num < hull->firstclipnode || num > hull->lastclipnode)
		Sys_Error ("SV_RecursiveHullCheck: bad node number");

//
// find the point distances
//
	node = hull->clipnodes + num;
	plane = hull->planes + node->planenum;

	if (plane->type < 3)
	{
		t1 = p1[plane->type] - plane->dist;
		t2 = p2[plane->type] - plane->dist;
	}
	else
	{
		t1 = DotProduct (plane->normal, p1) - plane->dist;
		t2 = DotProduct (plane->normal, p2) - plane->dist;
	}

	if (t1 >= 0 && t2 >= 0)
		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
	if (t1 < 0 && t2 < 0)
		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);

// put the crosspoint DIST_EPSILON pixels on the near side
	if (t1 < 0)
		frac = (t1 + DIST_EPSILON)/(t1-t2);
	else
		frac = (t1 - DIST_EPSILON)/(t1-t2);
	if (frac < 0)
		frac = 0;
	if (frac > 1)
		frac = 1;

	midf = p1f + (p2f - p1f)*frac;
	for (i=0 ; i<3 ; i++)
		mid[i] = p1[i] + frac*(p2[i] - p1[i]);

	side = (t1 < 0);

// move up to the node
	if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
		return false;

	if (HullPointContents (hull, node->children[side^1], mid)
	!= CONTENTS_SOLID)
// go past the node
		return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);

	if (trace->allsolid)
		return false;		// never got out of the solid area

//==================
// the other side of the node is solid, this is the impact point
//==================
	if (!side)
	{
		VectorCopy (plane->normal, trace->plane.normal);
		trace->plane.dist = plane->dist;
	}
	else
	{
		VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
		trace->plane.dist = -plane->dist;
	}
#if 0
	while (HullPointContents (hull, hull->firstclipnode, mid)
	== CONTENTS_SOLID)
	{ // shouldn't really happen, but does occasionally
		frac -= 0.1;
		if (frac < 0)
		{
			trace->fraction = midf;
			VectorCopy (mid, trace->endpos);
			//Con_DPrintf ("backup past 0\n");
			return false;
		}
		midf = p1f + (p2f - p1f)*frac;
		for (i=0 ; i<3 ; i++)
			mid[i] = p1[i] + frac*(p2[i] - p1[i]);
	}
#endif
	trace->fraction = midf;
	VectorCopy (mid, trace->endpos);

	return false;
}
Пример #9
0
/*
=================
CL_UpdateLightning
=================
*/
void CL_UpdateLightning (void)
{
	int			i, j;
	beam_t		*b;
	vec3_t		dist, org, beamstart, beamend;
	float		d, yaw, pitch, forward;
	entity_t	*ent;
//	qboolean	sparks = false;

	num_temp_entities = 0;

	// update lightning
	for (i = 0, b = cl_beams ; i < MAX_BEAMS ; i++, b++)
	{
		if (!b->model || BEAM_INACTIVE(b))
			continue;

		// if coming from the player, update the start position
		if (b->entity == cl.viewentity)
		{
			VectorCopy (cl_entities[cl.viewentity].origin, b->start);
			// joe: using koval's [sons]Quake code
			b->start[2] += cl.crouch;
			if (!cls.demorecording && cl_truelightning.value)
			{
				vec3_t	forward, v, org, ang;
				float	f, delta;
				trace_t	trace;

				f = bound(0, cl_truelightning.value, 1);

				VectorSubtract (playerbeam_end, cl_entities[cl.viewentity].origin, v);
		//		v[2] -= 22;		// adjust for view height
				v[2] -= cl.viewheight;		// adjust for view height
				vectoangles (v, ang);

				// lerp pitch
				ang[0] = -ang[0];
				if (ang[0] < -180)
					ang[0] += 360;
				ang[0] += (cl.viewangles[0] - ang[0]) * f;

				// lerp yaw
				delta = cl.viewangles[1] - ang[1];
				if (delta > 180)
					delta -= 360;
				if (delta < -180)
					delta += 360;
				ang[1] += delta * f;
				ang[2] = 0;

				AngleVectors (ang, forward, NULL, NULL);
				VectorScale (forward, 600, forward);
				VectorCopy (cl_entities[cl.viewentity].origin, org);
				org[2] += 16;
				VectorAdd(org, forward, b->end);

				memset (&trace, 0, sizeof(trace_t));
				if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, org, b->end, &trace))
					VectorCopy (trace.endpos, b->end);
			}
		}

		// calculate pitch and yaw
		VectorSubtract (b->end, b->start, dist);

		if (!dist[1] && !dist[0])
		{
			yaw = 0;
			pitch = (dist[2] > 0) ? 90 : 270;
		}
		else
		{
			yaw = atan2 (dist[1], dist[0]) * 180 / M_PI;
			if (yaw < 0)
				yaw += 360;
	
			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
			pitch = atan2 (dist[2], forward) * 180 / M_PI;
			if (pitch < 0)
				pitch += 360;
		}

		// add new entities for the lightning
		VectorCopy (b->start, org);
		VectorCopy (b->start, beamstart);
		d = VectorNormalize (dist);
		VectorScale (dist, 30, dist);

		for ( ; d > 0 ; d -= 30)
		{
			if (qmb_initialized && gl_part_lightning.value)
			{
				VectorAdd(org, dist, beamend);
				for (j=0 ; j<3 ; j++)
					beamend[j] += (b->entity != cl.viewentity) ? (rand() % 40) - 20 : (rand() % 16) - 8;
				QMB_LightningBeam (beamstart, beamend);

				// JT040905 - glowing lightning.
				CL_NewDlight (i, beamend, 200 + (rand() & 31), 0.1, lt_blue);
				CL_NewDlight (i, beamstart, 200 + (rand() & 31), 0.1, lt_blue);
				// end

				VectorCopy (beamend, beamstart);
			}
			else
			{
				if (!(ent = CL_NewTempEntity()))
					return;
				VectorCopy (org, ent->origin);
				ent->model = b->model;
				ent->angles[0] = pitch;
				ent->angles[1] = yaw;
				ent->angles[2] = rand() % 360;
			}

#if 0
			if (qmb_initialized && gl_part_lightning.value && !sparks)
			{
				trace_t	trace;

				memset (&trace, 0, sizeof(trace_t));
				if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, org, beamend, &trace))
				{
					byte	col[3] = {240, 150, 0};	// change color here 60, 100, 240

					QMB_GenSparks (trace.endpos, col, 3, 300, 0.25);	// 

					// JT 041105 - add second spark color
					/*
					byte	col[3] = {255, 204, 0};	// change color here

					QMB_GenSparks (trace.endpos, col, 2, 300, 0.25);
					*/
					// end

					QMB_Lightning_Splash (trace.endpos);
					sparks = true;
				}
			}
#endif
			VectorAdd(org, dist, org);
		}
	}
}
Пример #10
0
void R_DrawParticles (void)
{
	particle_t		*p, *kill;
	float			grav;
	int				i;
	float			time2, time3;
	float			time1;
	float			dvel, blend, blend1;
	float			frametime;
	vec3_t			up, right, neworg;
	float			scale, sscale;
	ParticleEmitter_t *ekill, *emt;

	if (gl_wireframe.value)
		return;

	glFogfv(GL_FOG_COLOR, color_black); //Done in actual function now (stops "triangle effect") - Eradicator
	glEnable (GL_BLEND);
	glBlendFunc (GL_ONE, GL_ONE);
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER,0.01);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glDepthMask(0);

	VectorScale (vup, 1, up);
	VectorScale (vright, 1, right);
	glMatrixMode(GL_TEXTURE);

	frametime = cl.time - cl.oldtime;
	time3 = frametime * 15;
	time2 = frametime * 10; // 15;
	time1 = frametime * 5;
	grav = frametime * sv_gravity.value * 0.05;
	dvel = 4*frametime;

	//remove expired emitters
	for ( ;; ) 
	{
		ekill = active_emitters;
		if (ekill && ekill->die < cl.time)
		{
			active_emitters = ekill->next;
			ekill->next = free_emitters;
			free_emitters = ekill;
			continue;
		}
		break;
	}

	//Do the particle logic/drawing
	for (emt=active_emitters ; emt ; emt=emt->next)
	{
		for ( ;; )
		{
			ekill = emt->next;
			//XYZ
			if (ekill && (ekill->die < cl.time))
			{
				emt->next = ekill->next;
				ekill->next = free_emitters;
				free_emitters = ekill;
				continue;
			}
			break;
		}

		if (emt->nexttick < cl.time) {
			vec3_t length;
			VectorSubtract(emt->origin, r_refdef.vieworg, length);
			//dont emit if we are to far away to see it
			if (Length(length) < 600.0f) {
				for (i=0; i<emt->count; i++) {
					InitParticleFromEffect(emt->effect,emt->origin);
				}
			}
			emt->nexttick = cl.time + emt->tick;
		}
	}

	//remove expired particles
	for ( ;; ) 
	{
		kill = active_particles;
		if (kill && kill->die < cl.time)
		{
			active_particles = kill->next;
			kill->next = free_particles;
			free_particles = kill;
			continue;
		}
		break;
	}

	//Do the particle logic/drawing
	for (p=active_particles ; p ; p=p->next)
	{
		for ( ;; )
		{
			kill = p->next;
			//XYZ
			if (kill && ((kill->die < cl.time) || (kill->numbounces <= 0)))
			{
				p->next = kill->next;
				kill->next = free_particles;
				free_particles = kill;
				continue;
			}
			break;
		}

		scale = p->size;
		p->size += p->growspeed*frametime;

		//calculate color based on life ...
		blend = (p->die-cl.time)/p->lifetime;
		blend1 = 1-blend;
		for (i=0; i<3; i++) {
			p->color[i] = p->startcolor[i] * blend + p->endcolor[i] * blend1;
		}

		if ((p->die - cl.time) < 0.5) {
			float fade = 2*(p->die - cl.time);
			glColor4f(p->color[0]*fade, p->color[1]*fade, p->color[2]*fade, fade);
		} else {
			glColor3fv(&p->color[0]);
		}

		GL_Bind(p->texture);
		glBlendFunc (p->srcblend, p->dstblend);

		//Align with velocity
		if (p->velaligned){
			float lscale;
			VectorCopy (p->vel, up);
			VectorNormalize(up);
			CrossProduct(vpn,up,right);
			VectorNormalize(right);
			lscale = (Length(p->vel)*p->velscale);
			VectorScale(up,lscale,up);
		} else {
			VectorCopy (vup, up);
			VectorCopy (vright, right);
		}

		glLoadIdentity();
		glTranslatef(0.5,0.5,0);
		glRotatef(p->rot,0,0,1);
		glTranslatef(-0.5,-0.5,0);

		sscale = -scale/4;
		VectorMA(p->org,sscale,up,neworg);
		VectorMA(neworg,sscale,right,neworg);

                // draw the particle as two triangles
                scale /= 2;
		glBegin(GL_TRIANGLE_FAN);
		glTexCoord2f (0,0);
		glVertex3fv (neworg);
		glTexCoord2f (0,1);
		glVertex3f (neworg[0] + up[0]*scale, neworg[1] + up[1]*scale,
                            neworg[2] + up[2]*scale);
		glTexCoord2f (1,1);
		glVertex3f (neworg[0] + up[0]*scale + right[0]*scale, neworg[1] + up[1]*scale + right[1]*scale,
                            neworg[2] + up[2]*scale + right[2]*scale);
		glTexCoord2f (1,0);
		glVertex3f (neworg[0] + right[0]*scale, neworg[1] + right[1]*scale,
                            neworg[2] + right[2]*scale);
		glEnd();
                scale *= 2;

		//calculate new position/rotation
		neworg[0] = p->org[0]+p->vel[0]*frametime;
		neworg[1] = p->org[1]+p->vel[1]*frametime;
		neworg[2] = p->org[2]+p->vel[2]*frametime;
		p->rot = p->rot+p->rspeed*frametime;

		//do collision detection
		{
			trace_t	trace;
			float	d;

			memset (&trace, 0, sizeof(trace));
			trace.fraction = 1;
			SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, p->org, neworg, &trace);

			if (trace.fraction < 1) {
				vec3_t tangent;
				//calc reflection vector
				d = DotProduct (p->vel, trace.plane.normal);
				VectorMA (p->vel, -2*d, trace.plane.normal, p->vel);
				VectorScale(p->vel,0.33,p->vel);
				VectorCopy(trace.endpos,p->org);
				//XYZ
				p->numbounces--;

				if (p->spawn) {
					CrossProduct(trace.plane.normal,p->vel,tangent);
					if (p->spawn->align == align_surf) {
						R_SpawnDecal(p->org, trace.plane.normal, tangent, p->spawn);
					} else {
						InitParticleFromEffect(p->spawn, p->org);
					}
				}
			} else {
				VectorCopy(neworg,p->org);
			}
		}

		for (i=0; i<3; i++) {
			p->vel[i] += p->gravity[i]*frametime;
		}
		
		for (i=0; i<3; i++) {
			p->vel[i] *= p->drag[i];
		}
	}

	glDepthMask(1);
	glDisable (GL_BLEND);
	glDisable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER,0.666);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	//XYZ
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glFogfv(GL_FOG_COLOR, fog_color); //Done in actual function now (stops "triangle effect") - Eradicator
}