Index: darkplaces/cl_main.c
diff -u darkplaces/cl_main.c:1.258 darkplaces/cl_main.c:1.259
--- darkplaces/cl_main.c:1.258	Tue Feb  6 03:43:07 2007
+++ darkplaces/cl_main.c	Thu Feb  8 10:57:20 2007
@@ -576,7 +576,7 @@
 	}
 }
 
-void CL_AllocDlight(entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
+void CL_AllocLightFlash(entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
 {
 	int i;
 	dlight_t *dl;
@@ -615,6 +615,7 @@
 	Matrix4x4_OriginFromMatrix(&dl->matrix, dl->origin);
 	CL_FindNonSolidLocation(dl->origin, dl->origin, 6);
 	Matrix4x4_SetOrigin(&dl->matrix, dl->origin[0], dl->origin[1], dl->origin[2]);
+	Matrix4x4_Scale(&dl->matrix, radius, 1);
 	dl->radius = radius;
 	dl->color[0] = red;
 	dl->color[1] = green;
@@ -629,7 +630,10 @@
 		dl->die = cl.time + lifetime;
 	else
 		dl->die = 0;
-	dl->cubemapnum = cubemapnum;
+	if (cubemapnum > 0)
+		dpsnprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", cubemapnum);
+	else
+		dl->cubemapname[0] = 0;
 	dl->style = style;
 	dl->shadow = shadowenable;
 	dl->corona = corona;
@@ -640,8 +644,7 @@
 	dl->specularscale = specularscale;
 }
 
-// called before entity relinking
-void CL_DecayLights(void)
+void CL_DecayLightFlashes(void)
 {
 	int i, oldmax;
 	dlight_t *dl;
@@ -667,25 +670,17 @@
 	}
 }
 
-// called after entity relinking
-void CL_UpdateLights(void)
+// called before entity relinking
+void CL_RelinkLightFlashes(void)
 {
 	int i, j, k, l;
 	dlight_t *dl;
 	float frac, f;
 
-	r_refdef.numlights = 0;
 	if (r_dynamic.integer)
-	{
-		for (i = 0, dl = cl.dlights;i < cl.num_dlights;i++, dl++)
-		{
+		for (i = 0, dl = cl.dlights;i < cl.num_dlights && r_refdef.numlights < MAX_DLIGHTS;i++, dl++)
 			if (dl->radius)
-			{
-				R_RTLight_Update(dl, false);
-				r_refdef.lights[r_refdef.numlights++] = dl;
-			}
-		}
-	}
+				R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &dl->matrix, dl->color, dl->style, dl->cubemapname, dl->shadow, dl->corona, dl->coronasizescale, dl->ambientscale, dl->diffusescale, dl->specularscale, dl->flags);
 
 // light animations
 // 'm' is normal light, 'a' is no light, 'z' is double bright
@@ -780,10 +775,9 @@
 	//matrix4x4_t dlightmatrix;
 	int j, k, l;
 	effectnameindex_t trailtype;
-	float origin[3], angles[3], delta[3], lerp, dlightcolor[3], dlightradius, v2[3], d;
+	float origin[3], angles[3], delta[3], lerp, d;
 	entity_t *t;
 	model_t *model;
-	trace_t trace;
 	//entity_persistent_t *p = &e->persistent;
 	//entity_render_t *r = &e->render;
 	// skip inactive entities and world
@@ -963,7 +957,8 @@
 	// make the other useful stuff
 	CL_UpdateRenderEntity(&e->render);
 
-	// handle effects now that we know where this entity is in the world...
+	// handle particle trails and such effects now that we know where this
+	// entity is in the world...
 	if (e->render.model && e->render.model->soundfromcenter)
 	{
 		// bmodels are treated specially since their origin is usually '0 0 0'
@@ -974,10 +969,6 @@
 	else
 		Matrix4x4_OriginFromMatrix(&e->render.matrix, origin);
 	trailtype = EFFECT_NONE;
-	dlightradius = 0;
-	dlightcolor[0] = 0;
-	dlightcolor[1] = 0;
-	dlightcolor[2] = 0;
 	// LordHavoc: if the entity has no effects, don't check each
 	if (e->render.effects)
 	{
@@ -988,55 +979,19 @@
 			else
 				CL_EntityParticles(e);
 		}
-		if (e->render.effects & EF_DIMLIGHT)
-		{
-			dlightradius = max(dlightradius, 200);
-			dlightcolor[0] += 1.50f;
-			dlightcolor[1] += 1.50f;
-			dlightcolor[2] += 1.50f;
-		}
-		if (e->render.effects & EF_BRIGHTLIGHT)
-		{
-			dlightradius = max(dlightradius, 400);
-			dlightcolor[0] += 3.00f;
-			dlightcolor[1] += 3.00f;
-			dlightcolor[2] += 3.00f;
-		}
-		// LordHavoc: more effects
-		if (e->render.effects & EF_RED) // red
-		{
-			dlightradius = max(dlightradius, 200);
-			dlightcolor[0] += 1.50f;
-			dlightcolor[1] += 0.15f;
-			dlightcolor[2] += 0.15f;
-		}
-		if (e->render.effects & EF_BLUE) // blue
-		{
-			dlightradius = max(dlightradius, 200);
-			dlightcolor[0] += 0.15f;
-			dlightcolor[1] += 0.15f;
-			dlightcolor[2] += 1.50f;
-		}
 		if (e->render.effects & EF_FLAME)
-			CL_ParticleEffect(EFFECT_EF_FLAME, bound(0, cl.time - cl.oldtime, 0.1), origin, origin, vec3_origin, vec3_origin, NULL, 0);
+			CL_ParticleTrail(EFFECT_EF_FLAME, bound(0, cl.time - cl.oldtime, 0.1), origin, origin, vec3_origin, vec3_origin, NULL, 0, false, true);
 		if (e->render.effects & EF_STARDUST)
-			CL_ParticleEffect(EFFECT_EF_STARDUST, bound(0, cl.time - cl.oldtime, 0.1), origin, origin, vec3_origin, vec3_origin, NULL, 0);
+			CL_ParticleTrail(EFFECT_EF_STARDUST, bound(0, cl.time - cl.oldtime, 0.1), origin, origin, vec3_origin, vec3_origin, NULL, 0, false, true);
 		if (e->render.effects & (EF_FLAG1QW | EF_FLAG2QW))
 		{
 			// these are only set on player entities
 			CL_AddQWCTFFlagModel(e, (e->render.effects & EF_FLAG2QW) != 0);
 		}
 	}
-	// muzzleflash fades over time, and is offset a bit
+	// muzzleflash fades over time
 	if (e->persistent.muzzleflash > 0)
-	{
-		Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2);
-		trace = CL_TraceBox(origin, vec3_origin, vec3_origin, v2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false);
-		tempmatrix = e->render.matrix;
-		Matrix4x4_SetOrigin(&tempmatrix, trace.endpos[0], trace.endpos[1], trace.endpos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 150, e->persistent.muzzleflash * 4.0f, e->persistent.muzzleflash * 4.0f, e->persistent.muzzleflash * 4.0f, 0, 0, 0, -1, true, 0, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		e->persistent.muzzleflash -= bound(0, cl.time - cl.oldtime, 0.1) * 20;
-	}
 	// LordHavoc: if the model has no flags, don't check each
 	if (e->render.model && e->render.model->flags && (!e->state_current.tagentity && !(e->render.flags & RENDER_VIEWMODEL)))
 	{
@@ -1058,36 +1013,6 @@
 		else if (e->render.model->flags & EF_TRACER3)
 			trailtype = EFFECT_TR_VORESPIKE;
 	}
-	// LordHavoc: customizable glow
-	if (e->state_current.glowsize)
-	{
-		// * 4 for the expansion from 0-255 to 0-1023 range,
-		// / 255 to scale down byte colors
-		dlightradius = max(dlightradius, e->state_current.glowsize * 4);
-		VectorMA(dlightcolor, (1.0f / 255.0f), (unsigned char *)&palette_complete[e->state_current.glowcolor], dlightcolor);
-	}
-	// make the glow dlight
-	if (dlightradius > 0 && (dlightcolor[0] || dlightcolor[1] || dlightcolor[2]) && !(e->render.flags & RENDER_VIEWMODEL))
-	{
-		//dlightmatrix = e->render.matrix;
-		// hack to make glowing player light shine on their gun
-		//if (e->state_current.number == cl.viewentity/* && !chase_active.integer*/)
-		//	Matrix4x4_AdjustOrigin(&dlightmatrix, 0, 0, 30);
-		CL_AllocDlight(&e->render, &e->render.matrix, dlightradius, dlightcolor[0], dlightcolor[1], dlightcolor[2], 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-	}
-	// custom rtlight
-	if (e->state_current.lightpflags & PFLAGS_FULLDYNAMIC)
-	{
-		float light[4];
-		VectorScale(e->state_current.light, (1.0f / 256.0f), light);
-		light[3] = e->state_current.light[3];
-		if (light[0] == 0 && light[1] == 0 && light[2] == 0)
-			VectorSet(light, 1, 1, 1);
-		if (light[3] == 0)
-			light[3] = 350;
-		// FIXME: add ambient/diffuse/specular scales as an extension ontop of TENEBRAE_GFX_DLIGHTS?
-		CL_AllocDlight(&e->render, &e->render.matrix, light[3], light[0], light[1], light[2], 0, 0, e->state_current.skin, e->state_current.lightstyle, !(e->state_current.lightpflags & PFLAGS_NOSHADOW), (e->state_current.lightpflags & PFLAGS_CORONA) != 0, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-	}
 	// do trails
 	if (e->render.flags & RENDER_GLOWTRAIL)
 		trailtype = EFFECT_TR_GLOWTRAIL;
@@ -1100,7 +1025,7 @@
 		if (len > 0)
 			len = 1.0f / len;
 		VectorScale(vel, len, vel);
-		CL_ParticleEffect(trailtype, 1, e->persistent.trail_origin, origin, vel, vel, e, e->state_current.glowcolor);
+		CL_ParticleTrail(trailtype, 1, e->persistent.trail_origin, origin, vel, vel, e, e->state_current.glowcolor, false, true);
 	}
 	VectorCopy(origin, e->persistent.trail_origin);
 	// tenebrae's sprites are all additive mode (weird)
@@ -1139,10 +1064,18 @@
 	entity_t *ent;
 	int i;
 
-// start on the entity after the world
+	// process network entities
+	// first link the player
+	CL_UpdateNetworkEntity(cl.entities + cl.viewentity);
+
+	// set up the view
+	V_CalcRefdef();
+
+	// start on the entity after the world
+	// skip the player entity because it was already processed
 	for (i = 1;i < cl.num_entities;i++)
 	{
-		if (cl.entities_active[i])
+		if (cl.entities_active[i] && i != cl.viewentity)
 		{
 			ent = cl.entities + i;
 			if (ent->state_current.active)
@@ -1184,6 +1117,11 @@
 // note this is a recursive function, but it can never get in a runaway loop (because of the delayedlink flags)
 void CL_LinkNetworkEntity(entity_t *e)
 {
+	effectnameindex_t trailtype;
+	vec3_t origin;
+	vec3_t dlightcolor;
+	vec_t dlightradius;
+
 	// skip inactive entities and world
 	if (!e->state_current.active || e == cl.entities)
 		return;
@@ -1202,6 +1140,140 @@
 			return;
 	}
 
+	// create entity dlights associated with this entity
+	if (e->render.model && e->render.model->soundfromcenter)
+	{
+		// bmodels are treated specially since their origin is usually '0 0 0'
+		vec3_t o;
+		VectorMAM(0.5f, e->render.model->normalmins, 0.5f, e->render.model->normalmaxs, o);
+		Matrix4x4_Transform(&e->render.matrix, o, origin);
+	}
+	else
+		Matrix4x4_OriginFromMatrix(&e->render.matrix, origin);
+	trailtype = EFFECT_NONE;
+	dlightradius = 0;
+	dlightcolor[0] = 0;
+	dlightcolor[1] = 0;
+	dlightcolor[2] = 0;
+	// LordHavoc: if the entity has no effects, don't check each
+	if (e->render.effects)
+	{
+		if (e->render.effects & EF_BRIGHTFIELD)
+		{
+			if (gamemode == GAME_NEXUIZ)
+				trailtype = EFFECT_TR_NEXUIZPLASMA;
+		}
+		if (e->render.effects & EF_DIMLIGHT)
+		{
+			dlightradius = max(dlightradius, 200);
+			dlightcolor[0] += 1.50f;
+			dlightcolor[1] += 1.50f;
+			dlightcolor[2] += 1.50f;
+		}
+		if (e->render.effects & EF_BRIGHTLIGHT)
+		{
+			dlightradius = max(dlightradius, 400);
+			dlightcolor[0] += 3.00f;
+			dlightcolor[1] += 3.00f;
+			dlightcolor[2] += 3.00f;
+		}
+		// LordHavoc: more effects
+		if (e->render.effects & EF_RED) // red
+		{
+			dlightradius = max(dlightradius, 200);
+			dlightcolor[0] += 1.50f;
+			dlightcolor[1] += 0.15f;
+			dlightcolor[2] += 0.15f;
+		}
+		if (e->render.effects & EF_BLUE) // blue
+		{
+			dlightradius = max(dlightradius, 200);
+			dlightcolor[0] += 0.15f;
+			dlightcolor[1] += 0.15f;
+			dlightcolor[2] += 1.50f;
+		}
+		if (e->render.effects & EF_FLAME)
+			CL_ParticleTrail(EFFECT_EF_FLAME, 0, origin, origin, vec3_origin, vec3_origin, NULL, 0, true, false);
+		if (e->render.effects & EF_STARDUST)
+			CL_ParticleTrail(EFFECT_EF_STARDUST, 0, origin, origin, vec3_origin, vec3_origin, NULL, 0, true, false);
+	}
+	// muzzleflash fades over time, and is offset a bit
+	if (e->persistent.muzzleflash > 0 && r_refdef.numlights < MAX_DLIGHTS)
+	{
+		vec3_t v2;
+		vec3_t color;
+		trace_t trace;
+		matrix4x4_t tempmatrix;
+		Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2);
+		trace = CL_TraceBox(origin, vec3_origin, vec3_origin, v2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false);
+		Matrix4x4_Normalize(&tempmatrix, &e->render.matrix);
+		Matrix4x4_SetOrigin(&tempmatrix, trace.endpos[0], trace.endpos[1], trace.endpos[2]);
+		Matrix4x4_Scale(&tempmatrix, 150, 1);
+		VectorSet(color, e->persistent.muzzleflash * 4.0f, e->persistent.muzzleflash * 4.0f, e->persistent.muzzleflash * 4.0f);
+		R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &tempmatrix, color, -1, NULL, true, 0, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+	}
+	// LordHavoc: if the model has no flags, don't check each
+	if (e->render.model && e->render.model->flags && (!e->state_current.tagentity && !(e->render.flags & RENDER_VIEWMODEL)))
+	{
+		if (e->render.model->flags & EF_GIB)
+			trailtype = EFFECT_TR_BLOOD;
+		else if (e->render.model->flags & EF_ZOMGIB)
+			trailtype = EFFECT_TR_SLIGHTBLOOD;
+		else if (e->render.model->flags & EF_TRACER)
+			trailtype = EFFECT_TR_WIZSPIKE;
+		else if (e->render.model->flags & EF_TRACER2)
+			trailtype = EFFECT_TR_KNIGHTSPIKE;
+		else if (e->render.model->flags & EF_ROCKET)
+			trailtype = EFFECT_TR_ROCKET;
+		else if (e->render.model->flags & EF_GRENADE)
+		{
+			// LordHavoc: e->render.alpha == -1 is for Nehahra dem compatibility (cigar smoke)
+			trailtype = e->render.alpha == -1 ? EFFECT_TR_NEHAHRASMOKE : EFFECT_TR_GRENADE;
+		}
+		else if (e->render.model->flags & EF_TRACER3)
+			trailtype = EFFECT_TR_VORESPIKE;
+	}
+	// LordHavoc: customizable glow
+	if (e->state_current.glowsize)
+	{
+		// * 4 for the expansion from 0-255 to 0-1023 range,
+		// / 255 to scale down byte colors
+		dlightradius = max(dlightradius, e->state_current.glowsize * 4);
+		VectorMA(dlightcolor, (1.0f / 255.0f), (unsigned char *)&palette_complete[e->state_current.glowcolor], dlightcolor);
+	}
+	// make the glow dlight
+	if (dlightradius > 0 && (dlightcolor[0] || dlightcolor[1] || dlightcolor[2]) && !(e->render.flags & RENDER_VIEWMODEL) && r_refdef.numlights < MAX_DLIGHTS)
+	{
+		matrix4x4_t dlightmatrix;
+		Matrix4x4_Normalize(&dlightmatrix, &e->render.matrix);
+		// hack to make glowing player light shine on their gun
+		//if (e->state_current.number == cl.viewentity/* && !chase_active.integer*/)
+		//	Matrix4x4_AdjustOrigin(&dlightmatrix, 0, 0, 30);
+		Matrix4x4_Scale(&dlightmatrix, dlightradius, 1);
+		R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &dlightmatrix, dlightcolor, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+	}
+	// custom rtlight
+	if ((e->state_current.lightpflags & PFLAGS_FULLDYNAMIC) && r_refdef.numlights < MAX_DLIGHTS)
+	{
+		matrix4x4_t dlightmatrix;
+		float light[4];
+		VectorScale(e->state_current.light, (1.0f / 256.0f), light);
+		light[3] = e->state_current.light[3];
+		if (light[0] == 0 && light[1] == 0 && light[2] == 0)
+			VectorSet(light, 1, 1, 1);
+		if (light[3] == 0)
+			light[3] = 350;
+		// FIXME: add ambient/diffuse/specular scales as an extension ontop of TENEBRAE_GFX_DLIGHTS?
+		Matrix4x4_Normalize(&dlightmatrix, &e->render.matrix);
+		Matrix4x4_Scale(&dlightmatrix, light[3], 1);
+		R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &dlightmatrix, light, e->state_current.lightstyle, e->state_current.skin > 0 ? va("cubemaps/%i", e->state_current.skin) : NULL, !(e->state_current.lightpflags & PFLAGS_NOSHADOW), (e->state_current.lightpflags & PFLAGS_CORONA) != 0, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+	}
+	// do trail light
+	if (e->render.flags & RENDER_GLOWTRAIL)
+		trailtype = EFFECT_TR_GLOWTRAIL;
+	if (trailtype)
+		CL_ParticleTrail(trailtype, 0, origin, origin, vec3_origin, vec3_origin, NULL, e->state_current.glowcolor, true, false);
+
 	// don't show entities with no modelindex (note: this still shows
 	// entities which have a modelindex that resolved to a NULL model)
 	if (e->render.model && !(e->render.effects & EF_NODRAW) && r_refdef.numentities < r_refdef.maxentities)
@@ -1391,11 +1463,13 @@
 
 		if (b->lightning)
 		{
-			if (cl_beams_lightatend.integer)
+			if (cl_beams_lightatend.integer && r_refdef.numlights < MAX_DLIGHTS)
 			{
 				// FIXME: create a matrix from the beam start/end orientation
-				Matrix4x4_CreateTranslate(&tempmatrix, end[0], end[1], end[2]);
-				CL_AllocDlight (NULL, &tempmatrix, 200, 0.3, 0.7, 1, 0, 0, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+				vec3_t dlightcolor;
+				VectorSet(dlightcolor, 0.3, 0.7, 1);
+				Matrix4x4_CreateFromQuakeEntity(&tempmatrix, end[0], end[1], end[2], 0, 0, 0, 200);
+				R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &tempmatrix, dlightcolor, -1, NULL, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 			}
 			if (cl_beams_polygons.integer)
 				continue;
@@ -1540,40 +1614,34 @@
 	r_refdef.time = cl.time;
 	r_refdef.extraupdate = !r_speeds.integer;
 	r_refdef.numentities = 0;
+	r_refdef.numlights = 0;
 	r_view.matrix = identitymatrix;
 
+	cl.num_brushmodel_entities = 0;
+
 	if (cls.state == ca_connected && cls.signon == SIGNONS)
 	{
 		// prepare for a new frame
 		CL_LerpPlayer(CL_LerpPoint());
-		CL_DecayLights();
+		CL_DecayLightFlashes();
 		CL_ClearTempEntities();
 		V_DriftPitch();
 		V_FadeViewFlashs();
 
-		// move particles
-		CL_MoveParticles();
-		R_MoveExplosions();
-
-		cl.num_brushmodel_entities = 0;
-		// process network entities
-		// first link the player
-		CL_UpdateNetworkEntity(cl.entities + cl.viewentity);
-		// set up the view
-		V_CalcRefdef();
-		if (!csqc_loaded)
-		{
-			// now link the rest of the network entities
-			// (this is instead done in VM_R_RenderScene if csqc is loaded)
-			CL_UpdateEntities();
-		}
+		// now update all the network entities
+		CL_UpdateEntities();
 
+		CL_RelinkLightFlashes();
 		CSQC_RelinkAllEntities(ENTMASK_ENGINE | ENTMASK_ENGINEVIEWMODELS);
 
-		CL_UpdateLights();
 		CL_StairSmoothing();
 
-		// update the r_refdef time again because cl.time may have changed
+		// move particles
+		CL_MoveParticles();
+		R_MoveExplosions();
+
+		// update the r_refdef time again because cl.time may have changed in
+		// CL_LerpPoint()
 		r_refdef.time = cl.time;
 	}
 
Index: darkplaces/cl_parse.c
diff -u darkplaces/cl_parse.c:1.230 darkplaces/cl_parse.c:1.231
--- darkplaces/cl_parse.c:1.230	Tue Feb  6 03:43:08 2007
+++ darkplaces/cl_parse.c	Thu Feb  8 10:57:20 2007
@@ -2227,7 +2227,7 @@
 			color[2] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
 			CL_ParticleExplosion(pos);
 			Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-			CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+			CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 			S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
 			break;
 
@@ -2240,7 +2240,7 @@
 			color[1] = MSG_ReadByte() * (2.0f / 255.0f);
 			color[2] = MSG_ReadByte() * (2.0f / 255.0f);
 			Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-			CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+			CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 			S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
 			break;
 
@@ -2267,7 +2267,7 @@
 			color[1] = MSG_ReadByte() * (2.0f / 255.0f);
 			color[2] = MSG_ReadByte() * (2.0f / 255.0f);
 			Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-			CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+			CL_AllocLightFlash(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 			break;
 
 		case TE_FLAMEJET:
@@ -2326,7 +2326,7 @@
 			color[1] = tempcolor[1] * (2.0f / 255.0f);
 			color[2] = tempcolor[2] * (2.0f / 255.0f);
 			Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-			CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+			CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 			S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
 			break;
 
Index: darkplaces/cl_particles.c
diff -u darkplaces/cl_particles.c:1.179 darkplaces/cl_particles.c:1.180
--- darkplaces/cl_particles.c:1.179	Mon Jan 22 08:37:39 2007
+++ darkplaces/cl_particles.c	Thu Feb  8 10:57:20 2007
@@ -22,6 +22,7 @@
 
 #include "cl_collision.h"
 #include "image.h"
+#include "r_shadow.h"
 
 // must match ptype_t values
 particletype_t particletype[pt_total] =
@@ -536,7 +537,7 @@
 }
 
 static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount, float smokecount);
-void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor)
+void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles)
 {
 	vec3_t center;
 	matrix4x4_t tempmatrix;
@@ -602,7 +603,7 @@
 		// bullet hole
 		if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24);
 		CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_SUPERSPIKE)
 	{
@@ -635,7 +636,7 @@
 		// bullet hole
 		if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24);
 		CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_BLOOD)
 	{
@@ -658,7 +659,7 @@
 		// plasma scorch mark
 		if (cl_stainmaps.integer) R_Stain(center, 48, 96, 96, 96, 32, 128, 128, 128, 32);
 		CL_SpawnDecalParticleForPoint(center, 6, 6, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-		CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_GUNSHOT)
 	{
@@ -685,17 +686,17 @@
 		// bullet hole
 		if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24);
 		CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_EXPLOSION)
 	{
 		CL_ParticleExplosion(center);
-		CL_AllocDlight(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_EXPLOSIONQUAD)
 	{
 		CL_ParticleExplosion(center);
-		CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_TAREXPLOSION)
 	{
@@ -712,10 +713,10 @@
 		}
 		else
 			CL_ParticleExplosion(center);
-		CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_SMALLFLASH)
-		CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	else if (effectnameindex == EFFECT_TE_FLAMEJET)
 	{
 		count *= cl_particles_quality.value;
@@ -763,7 +764,7 @@
 			}
 		}
 		particle(particletype + pt_static, particlepalette[14], particlepalette[14], tex_particle, 30, 0, 256, 512, 0, 0, center[0], center[1], center[2], 0, 0, 0, 0, 0, 0, 0);
-		CL_AllocDlight(NULL, &tempmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_TEI_G3)
 		particle(particletype + pt_beam, 0xFFFFFF, 0xFFFFFF, tex_beam, 8, 0, 256, 256, 0, 0, originmins[0], originmins[1], originmins[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0);
@@ -779,7 +780,7 @@
 	else if (effectnameindex == EFFECT_TE_TEI_BIGEXPLOSION)
 	{
 		CL_ParticleExplosion(center);
-		CL_AllocDlight(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_TE_TEI_PLASMAHIT)
 	{
@@ -793,21 +794,21 @@
 		if (cl_particles_sparks.integer)
 			for (f = 0;f < count;f += 1.0f / cl_particles_quality.value)
 				particle(particletype + pt_spark, 0x2030FF, 0x80C0FF, tex_particle, 2.0f, 0, lhrandom(64, 255), 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 0, 465);
-		CL_AllocDlight(NULL, &tempmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_EF_FLAME)
 	{
 		count *= 300 * cl_particles_quality.value;
 		while (count-- > 0)
 			particle(particletype + pt_smoke, 0x6f0f00, 0xe3974f, tex_particle, 4, 0, lhrandom(64, 128), 384, -1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 16, 128);
-		CL_AllocDlight(NULL, &tempmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (effectnameindex == EFFECT_EF_STARDUST)
 	{
 		count *= 200 * cl_particles_quality.value;
 		while (count-- > 0)
 			particle(particletype + pt_static, 0x903010, 0xFFD030, tex_particle, 4, 0, lhrandom(64, 128), 128, 1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0.2, 0.8, 16, 128);
-		CL_AllocDlight(NULL, &tempmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+		CL_AllocLightFlash(NULL, &tempmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	}
 	else if (!strncmp(particleeffectname[effectnameindex], "TR_", 3))
 	{
@@ -815,17 +816,33 @@
 		float len, dec, qd;
 		int smoke, blood, bubbles, r, color;
 
-		if (effectnameindex == EFFECT_TR_ROCKET)
-			CL_AllocDlight(&ent->render, &ent->render.matrix, 200, 3.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-		else if (effectnameindex == EFFECT_TR_VORESPIKE)
+		if (spawndlight && r_refdef.numlights < MAX_DLIGHTS)
 		{
-			if (gamemode == GAME_PRYDON && !cl_particles_quake.integer)
-				CL_AllocDlight(&ent->render, &ent->render.matrix, 100, 0.3f, 0.6f, 1.2f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-			else
-				CL_AllocDlight(&ent->render, &ent->render.matrix, 200, 1.2f, 0.5f, 1.0f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+			vec4_t light;
+			Vector4Set(light, 0, 0, 0, 0);
+
+			if (effectnameindex == EFFECT_TR_ROCKET)
+				Vector4Set(light, 3.0f, 1.5f, 0.5f, 200);
+			else if (effectnameindex == EFFECT_TR_VORESPIKE)
+			{
+				if (gamemode == GAME_PRYDON && !cl_particles_quake.integer)
+					Vector4Set(light, 0.3f, 0.6f, 1.2f, 100);
+				else
+					Vector4Set(light, 1.2f, 0.5f, 1.0f, 200);
+			}
+			else if (effectnameindex == EFFECT_TR_NEXUIZPLASMA)
+				Vector4Set(light, 0.75f, 1.5f, 3.0f, 200);
+
+			if (light[3])
+			{
+				matrix4x4_t tempmatrix;
+				Matrix4x4_CreateFromQuakeEntity(&tempmatrix, originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, light[3]);
+				R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &tempmatrix, light, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+			}
 		}
-		else if (effectnameindex == EFFECT_TR_NEXUIZPLASMA)
-			CL_AllocDlight(&ent->render, &ent->render.matrix, 200, 0.75f, 1.5f, 3.0f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+
+		if (!spawnparticles)
+			return;
 
 		if (originmaxs[0] == originmins[0] && originmaxs[1] == originmins[1] && originmaxs[2] == originmins[2])
 			return;
@@ -997,7 +1014,11 @@
 		Con_Printf("CL_ParticleEffect_Fallback: no fallback found for effect %s\n", particleeffectname[effectnameindex]);
 }
 
-void CL_ParticleEffect(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor)
+// this is also called on point effects with spawndlight = true and
+// spawnparticles = true
+// it is called CL_ParticleTrail because most code does not want to supply
+// these parameters, only trail handling does
+void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles)
 {
 	vec3_t center;
 	qboolean found = false;
@@ -1039,16 +1060,31 @@
 					continue;
 
 				// spawn a dlight if requested
-				if (info->lightradiusstart > 0)
+				if (info->lightradiusstart > 0 && spawndlight)
 				{
 					matrix4x4_t tempmatrix;
 					if (info->trailspacing > 0)
 						Matrix4x4_CreateTranslate(&tempmatrix, originmaxs[0], originmaxs[1], originmaxs[2]);
 					else
 						Matrix4x4_CreateTranslate(&tempmatrix, center[0], center[1], center[2]);
-					CL_AllocDlight(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0], info->lightcolor[1], info->lightcolor[2], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+					if (info->lighttime > 0 && info->lightradiusfade > 0)
+					{
+						// light flash (explosion, etc)
+						// called when effect starts
+						CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0], info->lightcolor[1], info->lightcolor[2], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+					}
+					else
+					{
+						// glowing entity
+						// called by CL_LinkNetworkEntity
+						Matrix4x4_Scale(&tempmatrix, info->lightradiusstart, 1);
+						R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &tempmatrix, info->lightcolor, -1, info->lightcubemapnum > 0 ? va("cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+					}
 				}
 
+				if (!spawnparticles)
+					continue;
+
 				// spawn particles
 				tex = info->tex[0];
 				if (info->tex[1] > info->tex[0])
@@ -1106,7 +1142,12 @@
 		}
 	}
 	if (!found)
-		CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor);
+		CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles);
+}
+
+void CL_ParticleEffect(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor)
+{
+	CL_ParticleTrail(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, true, true);
 }
 
 /*
Index: darkplaces/client.h
diff -u darkplaces/client.h:1.164 darkplaces/client.h:1.165
--- darkplaces/client.h:1.164	Tue Feb  6 03:18:50 2007
+++ darkplaces/client.h	Thu Feb  8 10:57:20 2007
@@ -150,11 +150,7 @@
 	// color of light
 	// (worldlight: saved to .rtlights file)
 	vec3_t color;
-	// cubemap number to use on this light
-	// (dlight only)
-	int cubemapnum;
 	// cubemap name to use on this light
-	// (worldlight only)
 	// (worldlight: saved to .rtlights file)
 	char cubemapname[64];
 	// make light flash while selected
@@ -201,7 +197,7 @@
 	// (worldlight only)
 	struct dlight_s *next;
 	// embedded rtlight struct for renderer
-	// (renderer only)
+	// (worldlight only)
 	rtlight_t rtlight;
 }
 dlight_t;
@@ -997,7 +993,7 @@
 
 extern client_state_t cl;
 
-extern void CL_AllocDlight (entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags);
+extern void CL_AllocLightFlash (entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags);
 
 //=============================================================================
 
@@ -1170,6 +1166,7 @@
 int CL_ParticleEffectIndexForName(const char *name);
 const char *CL_ParticleEffectNameForIndex(int i);
 void CL_ParticleEffect(int effectindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor);
+void CL_ParticleTrail(int effectindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles);
 void CL_ParseParticleEffect (void);
 void CL_ParticleCube (const vec3_t mins, const vec3_t maxs, const vec3_t dir, int count, int colorbase, vec_t gravity, vec_t randomvel);
 void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, int count, int colorbase, int type);
@@ -1254,7 +1251,7 @@
 	int maxentities;
 
 	// renderable dynamic lights
-	dlight_t *lights[MAX_DLIGHTS];
+	rtlight_t lights[MAX_DLIGHTS];
 	int numlights;
 
 	// 8.8bit fixed point intensities for light styles
Index: darkplaces/clvm_cmds.c
diff -u darkplaces/clvm_cmds.c:1.32 darkplaces/clvm_cmds.c:1.33
--- darkplaces/clvm_cmds.c:1.32	Thu Feb  8 05:15:36 2007
+++ darkplaces/clvm_cmds.c	Thu Feb  8 10:57:20 2007
@@ -1,12 +1,12 @@
 #include "prvm_cmds.h"
 #include "csprogs.h"
 #include "cl_collision.h"
+#include "r_shadow.h"
 
 //============================================================================
 // Client
 //[515]: unsolved PROBLEMS
 //- finish player physics code (cs_runplayerphysics)
-//- fix R_AddDynamicLight
 //- EntWasFreed ?
 //- RF_DEPTHHACK is not like it should be
 //- add builtin that sets cl.viewangles instead of reading "input_angles" global
@@ -772,11 +772,14 @@
 	Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], cl_viewmodel_scale.value);
 }
 
+void CL_RelinkLightFlashes(void);
 //#300 void() clearscene (EXT_CSQC)
 void VM_R_ClearScene (void)
 {
 	VM_SAFEPARMCOUNT(0, VM_R_ClearScene);
+	// clear renderable entity and light lists
 	r_refdef.numentities = 0;
+	r_refdef.numlights = 0;
 }
 
 //#301 void(float mask) addentities (EXT_CSQC)
@@ -789,6 +792,7 @@
 	VM_SAFEPARMCOUNT(1, VM_R_AddEntities);
 	drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
 	CSQC_RelinkAllEntities(drawmask);
+	CL_RelinkLightFlashes();
 
 	*prog->time = cl.time;
 	for(i=1;i<prog->num_edicts;i++)
@@ -915,8 +919,6 @@
 void VM_R_RenderScene (void) //#134
 {
 	VM_SAFEPARMCOUNT(0, VM_R_RenderScene);
-	// update all renderable network entities
-	CL_UpdateEntities();
 	R_RenderView();
 }
 
@@ -924,14 +926,17 @@
 void VM_R_AddDynamicLight (void)
 {
 	float		*pos, *col;
-	matrix4x4_t	tempmatrix;
+	matrix4x4_t	matrix;
 	VM_SAFEPARMCOUNT(3, VM_R_AddDynamicLight);
 
+	// if we've run out of dlights, just return
+	if (r_refdef.numlights >= MAX_DLIGHTS)
+		return;
+
 	pos = PRVM_G_VECTOR(OFS_PARM0);
 	col = PRVM_G_VECTOR(OFS_PARM2);
-	Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-	CL_AllocDlight(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), col[0], col[1], col[2], 500, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-	//CL_AllocDlight(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), col[0], col[1], col[2], 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+	Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
+	R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &matrix, col, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 }
 
 //============================================================================
@@ -1358,7 +1363,7 @@
 	CL_FindNonSolidLocation(pos, pos2, 10);
 	CL_ParticleExplosion(pos2);
 	Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-	CL_AllocDlight(NULL, &tempmatrix, 350, PRVM_G_VECTOR(OFS_PARM1)[0], PRVM_G_VECTOR(OFS_PARM1)[1], PRVM_G_VECTOR(OFS_PARM1)[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+	CL_AllocLightFlash(NULL, &tempmatrix, 350, PRVM_G_VECTOR(OFS_PARM1)[0], PRVM_G_VECTOR(OFS_PARM1)[1], PRVM_G_VECTOR(OFS_PARM1)[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 }
 
 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
@@ -1484,7 +1489,7 @@
 	pos = PRVM_G_VECTOR(OFS_PARM0);
 	CL_FindNonSolidLocation(pos, pos2, 4);
 	Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-	CL_AllocDlight(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM3)[0], PRVM_G_VECTOR(OFS_PARM3)[1], PRVM_G_VECTOR(OFS_PARM3)[2], PRVM_G_FLOAT(OFS_PARM1) / PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM2), 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+	CL_AllocLightFlash(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM3)[0], PRVM_G_VECTOR(OFS_PARM3)[1], PRVM_G_VECTOR(OFS_PARM3)[2], PRVM_G_FLOAT(OFS_PARM1) / PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM2), 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 }
 
 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
@@ -1627,7 +1632,7 @@
 	color[1] = tempcolor[1] * (2.0f / 255.0f);
 	color[2] = tempcolor[2] * (2.0f / 255.0f);
 	Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-	CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+	CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 	S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
 }
 
Index: darkplaces/csprogs.c
diff -u darkplaces/csprogs.c:1.23 darkplaces/csprogs.c:1.24
--- darkplaces/csprogs.c:1.23	Mon Feb  5 12:45:59 2007
+++ darkplaces/csprogs.c	Thu Feb  8 10:57:20 2007
@@ -321,7 +321,10 @@
 		//VectorCopy(cl.viewangles, oldangles);
 		*prog->time = cl.time;
 		CSQC_SetGlobals();
+		// clear renderable entity and light lists to prevent crashes if the
+		// CSQC_UpdateView function does not call R_ClearScene as it should
 		r_refdef.numentities = 0;
+		r_refdef.numlights = 0;
 		PRVM_ExecuteProgram (prog->globals.client->CSQC_UpdateView, CL_F_UPDATEVIEW);
 		//VectorCopy(oldangles, cl.viewangles);
 	CSQC_END
Index: darkplaces/r_light.c
diff -u darkplaces/r_light.c:1.136 darkplaces/r_light.c:1.137
--- darkplaces/r_light.c:1.136	Wed Jun  7 04:33:21 2006
+++ darkplaces/r_light.c	Thu Feb  8 10:57:20 2007
@@ -77,6 +77,7 @@
 	int i, lnum, flag;
 	float cscale, scale, viewdist, dist;
 	dlight_t *light;
+	rtlight_t *rtlight;
 	if (r_coronas.value < 0.01)
 		return;
 	R_Mesh_Matrix(&identitymatrix);
@@ -93,17 +94,17 @@
 	}
 	for (i = 0;i < r_refdef.numlights;i++)
 	{
-		light = r_refdef.lights[i];
-		if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_view.forward) - viewdist)) >= 24.0f && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
+		rtlight = &r_refdef.lights[i];
+		if ((rtlight->flags & flag) && rtlight->corona * r_coronas.value > 0 && (dist = (DotProduct(rtlight->shadoworigin, r_view.forward) - viewdist)) >= 24.0f && CL_TraceBox(rtlight->shadoworigin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
 		{
-			cscale = light->corona * r_coronas.value * 0.25f;
-			scale = light->rtlight.radius * light->rtlight.coronasizescale;
+			cscale = rtlight->corona * r_coronas.value * 0.25f;
+			scale = rtlight->radius * rtlight->coronasizescale;
 			if (gl_flashblend.integer)
 			{
 				cscale *= 4.0f;
 				scale *= 2.0f;
 			}
-			R_DrawSprite(GL_ONE, GL_ONE, lightcorona, NULL, true, light->origin, r_view.right, r_view.up, scale, -scale, -scale, scale, light->color[0] * cscale, light->color[1] * cscale, light->color[2] * cscale, 1);
+			R_DrawSprite(GL_ONE, GL_ONE, lightcorona, NULL, true, rtlight->shadoworigin, r_view.right, r_view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
 		}
 	}
 }
@@ -133,14 +134,14 @@
 	{
 		int i;
 		float f, v[3];
-		dlight_t *light;
+		rtlight_t *light;
 		for (i = 0;i < r_refdef.numlights;i++)
 		{
-			light = r_refdef.lights[i];
-			Matrix4x4_Transform(&light->rtlight.matrix_worldtolight, p, v);
+			light = &r_refdef.lights[i];
+			Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
 			f = 1 - VectorLength2(v);
-			if (f > 0 && CL_TraceBox(p, vec3_origin, vec3_origin, light->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
-				VectorMA(ambientcolor, f, light->rtlight.currentcolor, ambientcolor);
+			if (f > 0 && CL_TraceBox(p, vec3_origin, vec3_origin, light->shadoworigin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
+				VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
 		}
 	}
 }
Index: darkplaces/r_shadow.c
diff -u darkplaces/r_shadow.c:1.305 darkplaces/r_shadow.c:1.306
--- darkplaces/r_shadow.c:1.305	Sat Feb  3 03:49:02 2007
+++ darkplaces/r_shadow.c	Thu Feb  8 10:57:21 2007
@@ -2135,16 +2135,33 @@
 	}
 }
 
-void R_RTLight_Update(dlight_t *light, int isstatic)
+void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, qboolean shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
 {
-	double scale;
-	rtlight_t *rtlight = &light->rtlight;
+	// if this light has been compiled before, free the associated data
 	R_RTLight_Uncompile(rtlight);
+
+	// clear it completely to avoid any lingering data
 	memset(rtlight, 0, sizeof(*rtlight));
 
-	VectorCopy(light->origin, rtlight->shadoworigin);
-	VectorCopy(light->color, rtlight->color);
-	rtlight->radius = light->radius;
+	// copy the properties
+	Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, matrix);
+	Matrix4x4_OriginFromMatrix(matrix, rtlight->shadoworigin);
+	rtlight->radius = Matrix4x4_ScaleFromMatrix(matrix);
+	VectorCopy(color, rtlight->color);
+	rtlight->cubemapname[0] = 0;
+	if (cubemapname && cubemapname[0])
+		strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
+	rtlight->shadow = shadow;
+	rtlight->corona = corona;
+	rtlight->style = style;
+	rtlight->isstatic = isstatic;
+	rtlight->coronasizescale = coronasizescale;
+	rtlight->ambientscale = ambientscale;
+	rtlight->diffusescale = diffusescale;
+	rtlight->specularscale = specularscale;
+	rtlight->flags = flags;
+
+	// compute derived data
 	//rtlight->cullradius = rtlight->radius;
 	//rtlight->cullradius2 = rtlight->radius * rtlight->radius;
 	rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
@@ -2153,26 +2170,6 @@
 	rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
 	rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
 	rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
-	rtlight->cubemapname[0] = 0;
-	if (light->cubemapname[0])
-		strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
-	else if (light->cubemapnum > 0)
-		sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
-	rtlight->shadow = light->shadow;
-	rtlight->corona = light->corona;
-	rtlight->style = light->style;
-	rtlight->isstatic = isstatic;
-	rtlight->coronasizescale = light->coronasizescale;
-	rtlight->ambientscale = light->ambientscale;
-	rtlight->diffusescale = light->diffusescale;
-	rtlight->specularscale = light->specularscale;
-	rtlight->flags = light->flags;
-	Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
-	// this has to scale both rotate and translate because this is an already
-	// inverted matrix (it transforms from world to light space, not the other
-	// way around)
-	scale = 1.0 / rtlight->radius;
-	Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
 }
 
 // compiles rtlight geometry
@@ -2552,7 +2549,7 @@
 				R_DrawRTLight(&light->rtlight, visible);
 	if (r_refdef.rtdlight)
 		for (lnum = 0;lnum < r_refdef.numlights;lnum++)
-			R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
+			R_DrawRTLight(&r_refdef.lights[lnum], visible);
 
 	R_Shadow_RenderMode_End();
 }
@@ -2776,6 +2773,17 @@
 
 void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
 {
+	matrix4x4_t matrix;
+	// validate parameters
+	if (style < 0 || style >= MAX_LIGHTSTYLES)
+	{
+		Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
+		style = 0;
+	}
+	if (!cubemapname)
+		cubemapname = "";
+
+	// copy to light properties
 	VectorCopy(origin, light->origin);
 	light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
 	light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
@@ -2785,24 +2793,18 @@
 	light->color[2] = max(color[2], 0);
 	light->radius = max(radius, 0);
 	light->style = style;
-	if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
-	{
-		Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
-		light->style = 0;
-	}
 	light->shadow = shadowenable;
 	light->corona = corona;
-	if (!cubemapname)
-		cubemapname = "";
 	strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
 	light->coronasizescale = coronasizescale;
 	light->ambientscale = ambientscale;
 	light->diffusescale = diffusescale;
 	light->specularscale = specularscale;
 	light->flags = flags;
-	Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
 
-	R_RTLight_Update(light, true);
+	// update renderable light data
+	Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
+	R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
 }
 
 void R_Shadow_FreeWorldLight(dlight_t *light)
Index: darkplaces/r_shadow.h
diff -u darkplaces/r_shadow.h:1.59 darkplaces/r_shadow.h:1.60
--- darkplaces/r_shadow.h:1.59	Sat Feb  3 03:49:02 2007
+++ darkplaces/r_shadow.h	Thu Feb  8 10:57:21 2007
@@ -76,7 +76,7 @@
 
 extern rtlight_t *r_shadow_compilingrtlight;
 
-void R_RTLight_Update(dlight_t *light, int isstatic);
+void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, qboolean shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags);
 void R_RTLight_Compile(rtlight_t *rtlight);
 void R_RTLight_Uncompile(rtlight_t *rtlight);
 