diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c
index fe3e4b277..623809bc4 100644
--- a/engine/client/cl_ents.c
+++ b/engine/client/cl_ents.c
@@ -372,6 +372,15 @@ void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean
 		to->tagentity = MSG_ReadShort();
 		to->tagindex = MSG_ReadShort();
 	}
+	if (morebits & U_LIGHT)
+	{
+		to->light[0] = MSG_ReadShort();
+		to->light[1] = MSG_ReadShort();
+		to->light[2] = MSG_ReadShort();
+		to->light[3] = MSG_ReadShort();
+		to->lightstyle = MSG_ReadByte();
+		to->lightpflags = MSG_ReadByte();
+	}
 
 	VectorSubtract(to->origin, from->origin, move);
 
@@ -1500,6 +1509,10 @@ void CL_LinkPacketEntities (void)
 			else if (s1->effects & EF_DIMLIGHT)
 				CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], 200 + flicker, 0, 0);
 		}
+		if (s1->light[3])
+		{
+			CL_NewDlightRGB (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], s1->light[3], 0, s1->light[0]/1024.0f, s1->light[1]/1024.0f, s1->light[2]/1024.0f);
+		}
 
 		// if set to invisible, skip
 		if (s1->modelindex<1)
diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c
index 9323e4d32..6c07362ed 100644
--- a/engine/client/cl_input.c
+++ b/engine/client/cl_input.c
@@ -890,13 +890,14 @@ int CL_RemoveClientCommands(char *command)
 {
 	clcmdbuf_t *next, *first;
 	int removed = 0;
+	int len = strlen(command);
 
 	CL_AllowIndependantSendCmd(false);
 
 	if (!clientcmdlist)
 		return 0;
 
-	while(!strcmp(clientcmdlist->command, command))
+	while(!strncmp(clientcmdlist->command, command, len))
 	{
 		next = clientcmdlist->next;
 		Z_Free(clientcmdlist);
@@ -909,7 +910,7 @@ int CL_RemoveClientCommands(char *command)
 	first = clientcmdlist;
 	while(first->next)
 	{
-		if (!strcmp(first->next->command, command))
+		if (!strncmp(first->next->command, command, len))
 		{
 			next = first->next->next;
 			Z_Free(first->next);
diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c
index 5ead7d5be..7b690c620 100644
--- a/engine/client/cl_main.c
+++ b/engine/client/cl_main.c
@@ -369,6 +369,9 @@ void CL_SendConnectPacket (
 #ifdef PEXT_CSQC
 	fteprotextsupported |= PEXT_CSQC;
 #endif
+#ifdef PEXT_DPFLAGS
+	fteprotextsupported |= PEXT_DPFLAGS;
+#endif
 
 	fteprotextsupported &= ftepext;
 
@@ -1409,7 +1412,7 @@ void CL_SetInfo_f (void)
 	if (cls.state >= ca_connected)
 	{
 #ifdef Q2CLIENT
-		if (cls.protocol == CP_QUAKE2)
+		if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3)
 			cls.resendinfo = true;
 		else
 #endif
@@ -2186,7 +2189,7 @@ void CL_Download_f (void)
 
 	if (Cmd_IsInsecure())	//mark server specified downloads.
 	{
-		if (!strncmp(url, "game", 4) || !strcmp(url, "progs.dat") || !strcmp(url, "menu.dat") || !strcmp(url, "csqc.dat") || !strcmp(url, "qwprogs.dat") || strstr(url, "..") || strstr(url, ".dll") || strstr(url, ".so"))
+		if (!strnicmp(url, "game", 4) || !stricmp(url, "progs.dat") || !stricmp(url, "menu.dat") || !stricmp(url, "csprogs.dat") || !stricmp(url, "qwprogs.dat") || strstr(url, "..") || strstr(url, ".dll") || strstr(url, ".so"))
 		{	//yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar)
 			Con_Printf("Ignoring stuffed download of \"%s\" due to possible security risk\n", url);
 			return;
@@ -2632,7 +2635,7 @@ extern cvar_t cl_netfps;
 int		nopacketcount;
 void SNDDMA_SetUnderWater(qboolean underwater);
 float CL_FilterTime (double time, float wantfps);
-void Host_Frame (float time)
+void Host_Frame (double time)
 {
 	static double		time1 = 0;
 	static double		time2 = 0;
@@ -2640,7 +2643,7 @@ void Host_Frame (float time)
 	int			pass1, pass2, pass3;
 //	float fps;
 	float realframetime;
-	static float spare;
+	static double spare;
 
 	RSpeedLocals();
 
diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c
index 9e5bfbc30..6b0557cb4 100644
--- a/engine/client/cl_parse.c
+++ b/engine/client/cl_parse.c
@@ -680,6 +680,8 @@ void Sound_NextDownload (void)
 	else
 #endif
 	{
+		if (CL_RemoveClientCommands("modellist"))
+			Con_Printf("Multiple modellists\n");
 //		CL_SendClientCommand ("modellist %i 0", cl.servercount);
 		CL_SendClientCommand (true, modellist_name, cl.servercount, 0);
 	}
@@ -1796,7 +1798,7 @@ void CL_ParseSoundlist (void)
 		if (!str[0])
 			break;
 		numsounds++;
-		if (numsounds == MAX_SOUNDS)
+		if (numsounds >= MAX_SOUNDS)
 			Host_EndGame ("Server sent too many sound_precache");
 				
 //		if (strlen(str)>4)
@@ -1810,6 +1812,8 @@ void CL_ParseSoundlist (void)
 
 	if (n)
 	{
+		if (CL_RemoveClientCommands("soundlist"))
+			Con_Printf("Multiple soundlists\n");
 //		CL_SendClientCommand("soundlist %i %i", cl.servercount, n);
 		CL_SendClientCommand(true, soundlist_name, cl.servercount, n);
 		return;
@@ -1843,7 +1847,7 @@ void CL_ParseModellist (qboolean lots)
 		if (!str[0])
 			break;
 		nummodels++;
-		if (nummodels==MAX_MODELS)
+		if (nummodels>=MAX_MODELS)
 			Host_EndGame ("Server sent too many model_precache");
 		strcpy (cl.model_name[nummodels], str);
 
diff --git a/engine/client/console.c b/engine/client/console.c
index bac056f38..7ddae88d9 100644
--- a/engine/client/console.c
+++ b/engine/client/console.c
@@ -1336,5 +1336,4 @@ void Con_NotifyBox (char *text)
 
 	Con_Printf ("\n");
 	key_dest = key_game;
-	realtime = 0;				// put the cursor back to invisible
 }
diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c
index 227065d53..c73cf9df7 100644
--- a/engine/client/pr_csqc.c
+++ b/engine/client/pr_csqc.c
@@ -23,6 +23,7 @@ static csqctreadstate_t *csqcthreads;
 qboolean csqc_resortfrags;
 qboolean csqc_drawsbar;
 qboolean csqc_addcrosshair;
+static int num_csqc_edicts;
 
 cvar_t	pr_csmaxedicts = {"pr_csmaxedicts", "3072"};
 cvar_t	cl_csqcdebug = {"cl_csqcdebug", "0"};	//prints entity numbers which arrive (so I can tell people not to apply it to players...)
@@ -147,6 +148,7 @@ static void CSQC_FindGlobals(void)
 	fieldfloat(modelindex);	\
 	fieldvector(origin);	\
 	fieldvector(angles);	\
+	fieldvector(velocity);	\
 	fieldfloat(alpha);		/*transparency*/	\
 	fieldfloat(scale);		/*model scale*/		\
 	fieldfloat(fatness);	/*expand models X units along thier normals.*/	\
@@ -160,6 +162,8 @@ static void CSQC_FindGlobals(void)
 	fieldfloat(lerpfrac);	\
 	fieldfloat(renderflags);\
 	fieldfloat(forceshader);\
+	fieldfloat(dimension_hit);	\
+	fieldfloat(dimension_solid);	\
 							\
 	fieldfloat(drawmask);	/*So that the qc can specify all rockets at once or all bannanas at once*/	\
 	fieldfunction(predraw);	/*If present, is called just before it's drawn.*/	\
@@ -172,12 +176,14 @@ static void CSQC_FindGlobals(void)
 							\
 	fieldentity(chain);		\
 	fieldentity(groundentity);	\
+	fieldentity(owner);	\
 							\
 	fieldfloat(solid);		\
 	fieldvector(mins);		\
 	fieldvector(maxs);		\
-	fieldvector(absmins);	\
-	fieldvector(absmaxs);	\
+	fieldvector(size);		\
+	fieldvector(absmin);	\
+	fieldvector(absmax);	\
 	fieldfloat(hull);		/*(FTE_PEXT_HEXEN2)*/
 
 
@@ -206,6 +212,7 @@ typedef struct csqcedict_s
 
 	//add whatever you wish here
 	trailstate_t *trailstate;
+	link_t	area;
 } csqcedict_t;
 
 static csqcedict_t *csqc_edicts;	//consider this 'world'
@@ -342,69 +349,263 @@ void PF_fclose_progs (progfuncs_t *prinst);
 char *PF_VarString (progfuncs_t *prinst, int	first, struct globalvars_s *pr_globals);
 int QCEditor (progfuncs_t *prinst, char *filename, int line, int nump, char **parms);
 
+static model_t *CSQC_GetModelForIndex(int index);
+static void CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers);
 
-
-
-
-
-void CL_CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers)
+areanode_t	cs_areanodes[AREA_NODES];
+int			cs_numareanodes;
+areanode_t *CS_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
 {
+	areanode_t	*anode;
+	vec3_t		size;
+	vec3_t		mins1, maxs1, mins2, maxs2;
+
+	anode = &cs_areanodes[cs_numareanodes];
+	cs_numareanodes++;
+
+	ClearLink (&anode->trigger_edicts);
+	ClearLink (&anode->solid_edicts);
+	
+	if (depth == AREA_DEPTH)
+	{
+		anode->axis = -1;
+		anode->children[0] = anode->children[1] = NULL;
+		return anode;
+	}
+	
+	VectorSubtract (maxs, mins, size);
+	if (size[0] > size[1])
+		anode->axis = 0;
+	else
+		anode->axis = 1;
+	
+	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
+	VectorCopy (mins, mins1);	
+	VectorCopy (mins, mins2);	
+	VectorCopy (maxs, maxs1);	
+	VectorCopy (maxs, maxs2);	
+	
+	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
+	
+	anode->children[0] = CS_CreateAreaNode (depth+1, mins2, maxs2);
+	anode->children[1] = CS_CreateAreaNode (depth+1, mins1, maxs1);
+
+	return anode;
+}
+
+void CS_ClearWorld (void)
+{
+	int i;
+
+	memset (cs_areanodes, 0, sizeof(cs_areanodes));
+	cs_numareanodes = 0;
+	if (cl.worldmodel)
+		CS_CreateAreaNode (0, cl.worldmodel->mins, cl.worldmodel->maxs);
+	else
+	{
+		vec3_t mins, maxs;
+		int i;
+		for (i = 0; i < 3; i++)
+		{
+			mins[i] = -4096;
+			maxs[i] = 4096;
+		}
+		CS_CreateAreaNode (0, mins, maxs);
+	}
+
+	for (i = 1; i < num_csqc_edicts; i++)
+		CS_LinkEdict((csqcedict_t*)EDICT_NUM(csqcprogs, i), false);
+}
+
+void CS_UnlinkEdict (csqcedict_t *ent)
+{
+	if (!ent->area.prev)
+		return;		// not linked in anywhere
+	RemoveLink (&ent->area);
+	ent->area.prev = ent->area.next = NULL;
+}
+
+static void CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers)
+{
+	areanode_t *node;
+
+	if (ent->area.prev)
+		CS_UnlinkEdict (ent);	// unlink from old position
+
+	if (ent == csqc_edicts)
+		return;		// don't add the world
+
 	//FIXME: use some sort of area grid ?
-	VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmins);
-	VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmaxs);
+	VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin);
+	VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmax);
+
+	if ((int)ent->v->flags & FL_ITEM)
+	{
+		ent->v->absmin[0] -= 15;
+		ent->v->absmin[1] -= 15;
+		ent->v->absmax[0] += 15;
+		ent->v->absmax[1] += 15;
+	}
+	else
+	{	// because movement is clipped an epsilon away from an actual edge,
+		// we must fully check even when bounding boxes don't quite touch
+		ent->v->absmin[0] -= 1;
+		ent->v->absmin[1] -= 1;
+		ent->v->absmin[2] -= 1;
+		ent->v->absmax[0] += 1;
+		ent->v->absmax[1] += 1;
+		ent->v->absmax[2] += 1;
+	}
+
+	if (!ent->v->solid)
+		return;
+
+	// find the first node that the ent's box crosses
+	node = cs_areanodes;
+	while (1)
+	{
+		if (node->axis == -1)
+			break;
+		if (ent->v->absmin[node->axis] > node->dist)
+			node = node->children[0];
+		else if (ent->v->absmax[node->axis] < node->dist)
+			node = node->children[1];
+		else
+			break;		// crosses the node
+	}
+	
+// link it in	
+
+	if (ent->v->solid == SOLID_TRIGGER)
+		InsertLinkBefore (&ent->area, &node->trigger_edicts);
+	else
+		InsertLinkBefore (&ent->area, &node->solid_edicts);
+}
+
+typedef struct {
+	int type;
+	trace_t trace;
+	vec3_t boxmins;	//mins/max of total move.
+	vec3_t boxmaxs;
+	vec3_t start;
+	vec3_t end;
+	vec3_t mins;	//mins/max of ent
+	vec3_t maxs;
+	csqcedict_t *passedict;
+} moveclip_t;
+void CS_ClipToLinks ( areanode_t *node, moveclip_t *clip )
+{
+	model_t		*model;
+	trace_t		tr;
+	link_t		*l, *next;
+	csqcedict_t		*touch;
+
+	//work out who they are first.
+	for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
+	{
+		next = l->next;
+		touch = (csqcedict_t*)EDICT_FROM_AREA(l);
+		if (touch->v->solid == SOLID_NOT)
+			continue;
+		if (touch == clip->passedict)
+			continue;
+		if (touch->v->solid == SOLID_TRIGGER || touch->v->solid == SOLID_LADDER)
+			continue;
+
+		if (clip->type & MOVE_NOMONSTERS && touch->v->solid != SOLID_BSP)
+			continue;
+
+		if (clip->passedict)
+		{
+			// don't clip corpse against character
+			if (clip->passedict->v->solid == SOLID_CORPSE && (touch->v->solid == SOLID_SLIDEBOX || touch->v->solid == SOLID_CORPSE))
+				continue;
+			// don't clip character against corpse
+			if (clip->passedict->v->solid == SOLID_SLIDEBOX && touch->v->solid == SOLID_CORPSE)
+				continue;
+
+			if (!((int)clip->passedict->v->dimension_hit & (int)touch->v->dimension_solid))
+				continue;
+		}
+
+		if (clip->boxmins[0] > touch->v->absmax[0]
+		|| clip->boxmins[1] > touch->v->absmax[1]
+		|| clip->boxmins[2] > touch->v->absmax[2]
+		|| clip->boxmaxs[0] < touch->v->absmin[0]
+		|| clip->boxmaxs[1] < touch->v->absmin[1]
+		|| clip->boxmaxs[2] < touch->v->absmin[2] )
+			continue;
+
+		if (clip->passedict && clip->passedict->v->size[0] && !touch->v->size[0])
+			continue;	// points never interact
+
+	// might intersect, so do an exact clip
+		if (clip->trace.allsolid)
+			return;
+		if (clip->passedict)
+		{
+		 	if ((csqcedict_t*)PROG_TO_EDICT(svprogfuncs, touch->v->owner) == clip->passedict)
+				continue;	// don't clip against own missiles
+			if ((csqcedict_t*)PROG_TO_EDICT(svprogfuncs, clip->passedict->v->owner) == touch)
+				continue;	// don't clip against owner
+		}
+
+
+		if (!((int)clip->passedict->v->dimension_solid & (int)touch->v->dimension_hit))
+			continue;
+
+		model = CSQC_GetModelForIndex(touch->v->modelindex);
+		if (!model)
+			continue;
+		model->funcs.Trace(model, 0, 0, clip->start, clip->end, clip->mins, clip->maxs, &tr);
+		if (tr.fraction < clip->trace.fraction)
+		{
+			tr.ent = (void*)touch;
+			clip->trace = tr;
+		}
+	}
 }
 
 //FIXME: Not fully functional
-trace_t CL_Move(vec3_t v1, vec3_t mins, vec3_t maxs, vec3_t v2, float nomonsters, csqcedict_t *passedict)
+static trace_t CS_Move(vec3_t v1, vec3_t mins, vec3_t maxs, vec3_t v2, float nomonsters, csqcedict_t *passedict)
 {
-	int e;
-	csqcedict_t *ed;
-	vec3_t minb, maxb;
-	hull_t *hull;
+	moveclip_t clip;
 
-	trace_t	trace, trace2;
-
-	memset(&trace, 0, sizeof(trace));
-	trace.fraction = 1;
-	cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, v1, v2, mins, maxs, &trace);
+	if (cl.worldmodel)
+	{
+		cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, v1, v2, mins, maxs, &clip.trace);
+		clip.trace.ent = (void*)csqc_edicts;
+	}
+	else
+	{
+		memset(&clip.trace, 0, sizeof(clip.trace));
+		clip.trace.fraction = 1;
+		VectorCopy(v2, clip.trace.endpos);
+		clip.trace.ent = (void*)csqc_edicts;
+	}
 
 //why use trace.endpos instead?
 //so that if we hit a wall early, we don't have a box covering the whole world because of a shotgun trace.
-	minb[0] = ((v1[0] < trace.endpos[0])?v1[0]:trace.endpos[0]) - mins[0]-1;
-	minb[1] = ((v1[1] < trace.endpos[1])?v1[1]:trace.endpos[1]) - mins[1]-1;
-	minb[2] = ((v1[2] < trace.endpos[2])?v1[2]:trace.endpos[2]) - mins[2]-1;
-	maxb[0] = ((v1[0] > trace.endpos[0])?v1[0]:trace.endpos[0]) + maxs[0]+1;
-	maxb[1] = ((v1[1] > trace.endpos[1])?v1[1]:trace.endpos[1]) + maxs[1]+1;
-	maxb[2] = ((v1[2] > trace.endpos[2])?v1[2]:trace.endpos[2]) + maxs[2]+1;
-/*
-	for (e=1; e < *csqcprogs->parms->sv_num_edicts; e++)
-	{
-		ed = (void*)EDICT_NUM(csqcprogs, e);
-		if (ed->isfree)
-			continue;	//can't collide
-		if (!ed->v->solid)
-			continue;
-		if (ed->v->absmaxs[0] < minb[0] ||
-			ed->v->absmaxs[1] < minb[1] ||
-			ed->v->absmaxs[2] < minb[2] ||
-			ed->v->absmins[0] > maxb[0] ||
-			ed->v->absmins[1] > maxb[1] ||
-			ed->v->absmins[2] > maxb[2])
-			continue;
+	clip.boxmins[0] = ((v1[0] < clip.trace.endpos[0])?v1[0]:clip.trace.endpos[0]) - mins[0]-1;
+	clip.boxmins[1] = ((v1[1] < clip.trace.endpos[1])?v1[1]:clip.trace.endpos[1]) - mins[1]-1;
+	clip.boxmins[2] = ((v1[2] < clip.trace.endpos[2])?v1[2]:clip.trace.endpos[2]) - mins[2]-1;
+	clip.boxmaxs[0] = ((v1[0] > clip.trace.endpos[0])?v1[0]:clip.trace.endpos[0]) + maxs[0]+1;
+	clip.boxmaxs[1] = ((v1[1] > clip.trace.endpos[1])?v1[1]:clip.trace.endpos[1]) + maxs[1]+1;
+	clip.boxmaxs[2] = ((v1[2] > clip.trace.endpos[2])?v1[2]:clip.trace.endpos[2]) + maxs[2]+1;
 
-		hull = CL_HullForEntity(ed);
-		memset(&trace, 0, sizeof(trace));
-		trace.fraction = 1;
-		TransformedHullCheck(hull, v1, v2, &trace2, ed->v->angles);
-		trace2.ent = (void*)ed;
-		if (trace2.fraction < trace.fraction)
-			trace = trace2;
-	}
-*/
-	return trace;
+	VectorCopy(mins, clip.mins);
+	VectorCopy(maxs, clip.maxs);
+	VectorCopy(v1, clip.start);
+	VectorCopy(v2, clip.end);
+	clip.passedict = passedict;
+
+	CS_ClipToLinks(cs_areanodes, &clip);
+	return clip.trace;
 }
 
-
+void CS_CheckVelocity(csqcedict_t *ent)
+{
+}
 
 
 static void PF_cs_remove (progfuncs_t *prinst, struct globalvars_s *pr_globals)
@@ -420,7 +621,7 @@ static void PF_cs_remove (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 	}
 
 	P_DelinkTrailstate(&ed->trailstate);
-
+	CS_UnlinkEdict(ed);
 	ED_Free (prinst, (void*)ed);
 }
 
@@ -608,6 +809,12 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
 	out->frame1time = in->v->frame1time;
 	out->frame2time = in->v->frame2time;
 
+	if (in->v->colormap > 0 && in->v->colormap <= MAX_CLIENTS)
+	{
+		out->colormap = cl.players[(int)in->v->colormap-1].translations;
+		out->scoreboard = &cl.players[(int)in->v->colormap-1];
+	}
+
 	if (!in->v->alpha)
 		out->alpha = 1;
 	else
@@ -619,7 +826,7 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
 	out->skinnum = in->v->skin;
 	out->fatness = in->v->fatness;
 #ifdef Q3SHADERS
-	out->forcedshader = *(int*)&in->v->forceshader;
+	out->forcedshader = *(struct shader_s**)&in->v->forceshader;
 #endif
 
 	out->keynum = -1;
@@ -988,7 +1195,7 @@ static void PF_cs_SetOrigin(progfuncs_t *prinst, struct globalvars_s *pr_globals
 
 	VectorCopy(org, ent->v->origin);
 
-	CL_CS_LinkEdict(ent, false);
+	CS_LinkEdict(ent, false);
 }
 
 static void PF_cs_SetSize(progfuncs_t *prinst, struct globalvars_s *pr_globals)
@@ -1000,7 +1207,7 @@ static void PF_cs_SetSize(progfuncs_t *prinst, struct globalvars_s *pr_globals)
 	VectorCopy(mins, ent->v->mins);
 	VectorCopy(maxs, ent->v->maxs);
 
-	CL_CS_LinkEdict(ent, false);
+	CS_LinkEdict(ent, false);
 }
 
 static void PF_cs_traceline(progfuncs_t *prinst, struct globalvars_s *pr_globals)
@@ -1029,7 +1236,7 @@ static void PF_cs_traceline(progfuncs_t *prinst, struct globalvars_s *pr_globals
 
 	savedhull = ent->v->hull;
 	ent->v->hull = 0;
-	trace = CL_Move (v1, mins, maxs, v2, nomonsters, ent);
+	trace = CS_Move (v1, mins, maxs, v2, nomonsters, ent);
 	ent->v->hull = savedhull;
 	
 	*csqcg.trace_allsolid = trace.allsolid;
@@ -1062,7 +1269,7 @@ static void PF_cs_tracebox(progfuncs_t *prinst, struct globalvars_s *pr_globals)
 
 	savedhull = ent->v->hull;
 	ent->v->hull = 0;
-	trace = CL_Move (v1, mins, maxs, v2, nomonsters, ent);
+	trace = CS_Move (v1, mins, maxs, v2, nomonsters, ent);
 	ent->v->hull = savedhull;
 	
 	*csqcg.trace_allsolid = trace.allsolid;
@@ -1079,6 +1286,81 @@ static void PF_cs_tracebox(progfuncs_t *prinst, struct globalvars_s *pr_globals)
 		*csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_edicts);
 }
 
+static trace_t CS_Trace_Toss (csqcedict_t *tossent, csqcedict_t *ignore)
+{
+	int i;
+	int savedhull;
+	float gravity;
+	vec3_t move, end;
+	trace_t trace;
+	float maxvel = Cvar_Get("sv_maxvelocity", "2000", 0, "CSQC physics")->value;
+
+	vec3_t origin, velocity;
+
+	// this has to fetch the field from the original edict, since our copy is truncated
+	gravity = 1;//tossent->v->gravity;
+	if (!gravity)
+		gravity = 1.0;
+	gravity *= Cvar_Get("sv_gravity", "800", 0, "CSQC physics")->value * 0.05;
+
+	VectorCopy (tossent->v->origin, origin);
+	VectorCopy (tossent->v->velocity, velocity);
+
+	CS_CheckVelocity (tossent);
+
+	savedhull = tossent->v->hull;
+	tossent->v->hull = 0;
+	for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
+	{
+		velocity[2] -= gravity;
+		VectorScale (velocity, 0.05, move);
+		VectorAdd (origin, move, end);
+		trace = CS_Move (origin, tossent->v->mins, tossent->v->maxs, end, MOVE_NORMAL, tossent);
+		VectorCopy (trace.endpos, origin);
+
+		CS_CheckVelocity (tossent);
+
+		if (trace.fraction < 1 && trace.ent && (void*)trace.ent != ignore)
+			break;
+	}
+	tossent->v->hull = savedhull;
+
+	trace.fraction = 0; // not relevant
+	return trace;
+}
+static void PF_cs_tracetoss (progfuncs_t *prinst, struct globalvars_s *pr_globals)
+{
+	trace_t	trace;
+	csqcedict_t	*ent;
+	csqcedict_t	*ignore;
+
+	ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0);
+	if (ent == csqc_edicts)
+		Con_DPrintf("tracetoss: can not use world entity\n");
+	ignore = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1);
+
+	trace = CS_Trace_Toss (ent, ignore);
+
+	*csqcg.trace_allsolid = trace.allsolid;
+	*csqcg.trace_startsolid = trace.startsolid;
+	*csqcg.trace_fraction = trace.fraction;
+	*csqcg.trace_inwater = trace.inwater;
+	*csqcg.trace_inopen = trace.inopen;
+	VectorCopy (trace.endpos, csqcg.trace_endpos);
+	VectorCopy (trace.plane.normal, csqcg.trace_plane_normal);
+	pr_global_struct->trace_plane_dist =  trace.plane.dist;
+	if (trace.ent)
+		*csqcg.trace_ent = EDICT_TO_PROG(prinst, trace.ent);
+	else
+		*csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_edicts);
+}
+
+static int CS_PointContents(vec3_t org)
+{
+	if (!cl.worldmodel)
+		return FTECONTENTS_EMPTY;
+	return cl.worldmodel->hulls[0].funcs.HullPointContents(&cl.worldmodel->hulls[0], org);
+}
 static void PF_cs_pointcontents(progfuncs_t *prinst, struct globalvars_s *pr_globals)
 {
 	float	*v;
@@ -1086,7 +1368,7 @@ static void PF_cs_pointcontents(progfuncs_t *prinst, struct globalvars_s *pr_glo
 	
 	v = G_VECTOR(OFS_PARM0);
 
-	cont = cl.worldmodel->hulls[0].funcs.HullPointContents(&cl.worldmodel->hulls[0], v);
+	cont = CS_PointContents(v);
 	if (cont & FTECONTENTS_SOLID)
 		G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID;
 	else if (cont & FTECONTENTS_SKY)
@@ -2093,14 +2375,14 @@ void PF_cs_droptofloor (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 	end[2] -= 512;
 
 	VectorCopy (ent->v->origin, start);
-	trace = CL_Move (start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
+	trace = CS_Move (start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
 
 	if (trace.fraction == 1 || trace.allsolid)
 		G_FLOAT(OFS_RETURN) = 0;
 	else
 	{
 		VectorCopy (trace.endpos, ent->v->origin);
-		CL_CS_LinkEdict (ent, false);
+		CS_LinkEdict (ent, false);
 		ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
 		ent->v->groundentity = EDICT_TO_PROG(prinst, trace.ent);
 		G_FLOAT(OFS_RETURN) = 1;
@@ -2116,17 +2398,9 @@ static void PF_cs_copyentity (progfuncs_t *prinst, struct globalvars_s *pr_globa
 
 	memcpy(out->v, in->v, csqcentsize);
 
-	CL_CS_LinkEdict (out, false);
+	CS_LinkEdict (out, false);
 }
 
-//these are the builtins that still need to be added.
-#define PF_cs_tracetoss			PF_Fixme
-#define PF_cs_gettaginfo		PF_Fixme
-#define PS_cs_setattachment		PF_Fixme
-#define PF_cs_break				PF_Fixme
-#define PF_cs_walkmove			PF_Fixme
-#define PF_cs_checkbottom		PF_Fixme
-
 static void PF_cl_playingdemo (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 {
 	G_FLOAT(OFS_RETURN) = !!cls.demoplayback;
@@ -2269,6 +2543,94 @@ static void PF_shaderforname (progfuncs_t *prinst, struct globalvars_s *pr_globa
 #endif
 }
 
+qboolean CS_CheckBottom (csqcedict_t *ent)
+{
+	int savedhull;
+	vec3_t	mins, maxs, start, stop;
+	trace_t	trace;
+	int		x, y;
+	float	mid, bottom;
+
+	if (!cl.worldmodel)
+		return false;
+	
+	VectorAdd (ent->v->origin, ent->v->mins, mins);
+	VectorAdd (ent->v->origin, ent->v->maxs, maxs);
+
+// if all of the points under the corners are solid world, don't bother
+// with the tougher checks
+// the corners must be within 16 of the midpoint
+	start[2] = mins[2] - 1;
+	for	(x=0 ; x<=1 ; x++)
+		for	(y=0 ; y<=1 ; y++)
+		{
+			start[0] = x ? maxs[0] : mins[0];
+			start[1] = y ? maxs[1] : mins[1];
+			if (!(CS_PointContents (start) & FTECONTENTS_SOLID))
+				goto realcheck;
+		}
+
+//	c_yes++;
+	return true;		// we got out easy
+
+realcheck:
+//	c_no++;
+//
+// check it for real...
+//
+	start[2] = mins[2];
+	
+// the midpoint must be within 16 of the bottom
+	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
+	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
+	stop[2] = start[2] - 2*pm_stepheight;
+	trace = CS_Move (start, vec3_origin, vec3_origin, stop, true, ent);
+
+	if (trace.fraction == 1.0)
+		return false;
+	mid = bottom = trace.endpos[2];
+	
+// the corners must be within 16 of the midpoint	
+	for	(x=0 ; x<=1 ; x++)
+		for	(y=0 ; y<=1 ; y++)
+		{
+			start[0] = stop[0] = x ? maxs[0] : mins[0];
+			start[1] = stop[1] = y ? maxs[1] : mins[1];
+			
+			savedhull = ent->v->hull;
+			ent->v->hull = 0;
+			trace = CS_Move (start, vec3_origin, vec3_origin, stop, true, ent);
+			ent->v->hull = savedhull;
+			
+			if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
+				bottom = trace.endpos[2];
+			if (trace.fraction == 1.0 || mid - trace.endpos[2] > pm_stepheight)
+				return false;
+		}
+
+//	c_yes++;
+	return true;
+}
+static void PF_cs_checkbottom (progfuncs_t *prinst, struct globalvars_s *pr_globals)
+{
+	csqcedict_t	*ent;
+
+	ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0);
+
+	G_FLOAT(OFS_RETURN) = CS_CheckBottom (ent);
+}
+
+static void PF_cs_break (progfuncs_t *prinst, struct globalvars_s *pr_globals)
+{
+	Con_Printf ("break statement\n");
+#ifdef TEXTEDITOR
+	(*prinst->pr_trace)++;
+#endif
+}
+
+static void PF_cs_walkmove (progfuncs_t *prinst, struct globalvars_s *pr_globals)
+{
+}
 
 #define PF_FixTen PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme
 
@@ -2277,6 +2639,10 @@ static void PF_shaderforname (progfuncs_t *prinst, struct globalvars_s *pr_globa
 //PF_cs_ - works in csqc only (dependant upon globals or fields)
 //PF_cl_ - works in csqc and menu (if needed...)
 
+//these are the builtins that still need to be added.
+#define PF_cs_gettaginfo		PF_Fixme
+#define PS_cs_setattachment		PF_Fixme
+
 //warning: functions that depend on globals are bad, mkay?
 static builtin_t csqc_builtins[] = {
 //0
@@ -2703,7 +3069,6 @@ static int csqc_numbuiltins = sizeof(csqc_builtins)/sizeof(csqc_builtins[0]);
 
 static jmp_buf csqc_abort;
 static progparms_t csqcprogparms;
-static int num_csqc_edicts;
 
 
 
@@ -2769,17 +3134,32 @@ void CSQC_Shutdown(void)
 qbyte *CSQC_PRLoadFile (char *path, void *buffer, int bufsize)
 {
 	qbyte *file;
-	//pretend it doesn't 
-	file = COM_LoadStackFile(path, buffer, bufsize);
 
-#ifndef _DEBUG
-	if (!cls.demoplayback)	//allow any csqc when playing a demo
-		if (!strcmp(path, "csprogs.dat"))	//Fail to load any csprogs who's checksum doesn't match.
-			if (Com_BlockChecksum(buffer, com_filesize) != csqcchecksum)
-				return NULL;
-#endif
+	if (!strcmp(path, "csprogs.dat"))
+	{
+		char newname[MAX_QPATH];
+		_snprintf(newname, MAX_PATH, "csprogsvers/%x.dat", csqcchecksum);
 
-	return file;
+		file = COM_LoadStackFile(newname, buffer, bufsize);
+		if (file)
+			if (Com_BlockChecksum(file, com_filesize) == csqcchecksum)	//and the user wasn't trying to be cunning.
+				return file;
+
+		file = COM_LoadStackFile(path, buffer, bufsize);
+		if (!cls.demoplayback)	//allow them to use csprogs.dat if playing a demo, and don't care about the checksum
+		{
+			if (Com_BlockChecksum(file, com_filesize) != csqcchecksum)
+				return NULL;	//not valid
+
+			//back it up
+			COM_WriteFile(newname, file, com_filesize);
+		}
+
+		return file;
+
+	}
+
+	return COM_LoadStackFile(path, buffer, bufsize);;
 }
 
 double  csqctime;
@@ -2854,9 +3234,12 @@ qboolean CSQC_Init (unsigned int checksum)
 			return false;
 		}
 
+		num_csqc_edicts = 0;
+		CS_ClearWorld();
+
 		PF_InitTempStrings(csqcprogs);
 
-		memset(csqcent, 0, sizeof(*csqcent)*maxcsqcentities);
+		memset(csqcent, 0, sizeof(*csqcent)*maxcsqcentities);	//clear the server->csqc entity translations.
 		
 		csqcentsize = PR_InitEnts(csqcprogs, pr_csmaxedicts.value);
 		
diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h
index a7f07f026..b4bd8fed7 100644
--- a/engine/client/quakedef.h
+++ b/engine/client/quakedef.h
@@ -230,7 +230,7 @@ void Host_Shutdown(void);
 void VARGS Host_Error (char *error, ...);
 void VARGS Host_EndGame (char *message, ...);
 qboolean Host_SimulationTime(float time);
-void Host_Frame (float time);
+void Host_Frame (double time);
 void Host_Quit_f (void);
 void VARGS Host_ClientCommands (char *fmt, ...);
 void Host_ShutdownServer (qboolean crash);
diff --git a/engine/client/r_part.c b/engine/client/r_part.c
index 41e83d570..bce0d8d43 100644
--- a/engine/client/r_part.c
+++ b/engine/client/r_part.c
@@ -372,6 +372,7 @@ void P_ParticleEffect_f(void)
 	particle_t *parts;
 	beamseg_t *beamsegs;
 	skytris_t *st;
+	qboolean settype = false;
 
 	part_type_t *ptype;
 	int pnum, assoc;
@@ -688,7 +689,7 @@ void P_ParticleEffect_f(void)
 				ptype->type = PT_DECAL;
 			else
 				ptype->type = PT_NORMAL;
-
+			settype = true;
 		}
 		else if (!strcmp(var, "isbeam"))
 		{
@@ -876,14 +877,17 @@ void P_ParticleEffect_f(void)
 	if (ptype->friction)
 		ptype->flags |= PT_FRICTION;
 
-	if (ptype->type == PT_NORMAL && !*ptype->texname)
-		ptype->type = PT_SPARK;
-	if (ptype->type == PT_SPARK)
+	if (!settype)
 	{
-		if (*ptype->texname)
-			ptype->type = PT_TEXTUREDSPARK;
-		if (ptype->scale)
-			ptype->type = PT_SPARKFAN;
+		if (ptype->type == PT_NORMAL && !*ptype->texname)
+			ptype->type = PT_SPARK;
+		if (ptype->type == PT_SPARK)
+		{
+			if (*ptype->texname)
+				ptype->type = PT_TEXTUREDSPARK;
+			if (ptype->scale)
+				ptype->type = PT_SPARKFAN;
+		}
 	}
 
 	if (ptype->rampmode && !ptype->ramp)
diff --git a/engine/client/renderer.c b/engine/client/renderer.c
index bc81f1d3b..5aa3c37af 100644
--- a/engine/client/renderer.c
+++ b/engine/client/renderer.c
@@ -1267,6 +1267,7 @@ void R_SetRenderer(int wanted)
 	VID_SetPalette			= ri->VID_SetPalette;
 	VID_ShiftPalette		= ri->VID_ShiftPalette;
 	VID_GetRGBInfo			= ri->VID_GetRGBInfo;
+	VID_SetWindowCaption	= ri->VID_SetWindowCaption;
 
 	Media_ShowFrame8bit			= ri->Media_ShowFrame8bit;
 	Media_ShowFrameRGBA_32		= ri->Media_ShowFrameRGBA_32;
diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c
index b47200a03..2d3f7afd7 100644
--- a/engine/client/sys_win.c
+++ b/engine/client/sys_win.c
@@ -697,8 +697,7 @@ void Sys_InitFloatTime (void)
 }
 
 #endif
-// DWORD starttime;
-double Sys_DoubleTime (void)
+unsigned int Sys_Milliseconds (void)
 {
 	static DWORD starttime;
 	static qboolean first = true;
@@ -712,19 +711,24 @@ double Sys_DoubleTime (void)
 		starttime = now;
 		return 0.0;
 	}
-	
+	/*
 	if (now < starttime) // wrapped?
 	{
 		double r;
-		r = (now / 1000.0) + (LONG_MAX - starttime / 1000.0);
+		r = (now) + (LONG_MAX - starttime);
 		starttime = now;
 		return r;
 	}
 
 	if (now - starttime == 0)
 		return 0.0;
+*/
+	return (now - starttime);
+}
 
-	return (now - starttime) / 1000.0;
+double Sys_DoubleTime (void)
+{
+	return Sys_Milliseconds()/1000.f;
 }
 
 
@@ -1090,21 +1094,14 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
 	{
 		SV_Init (&parms);
 
-		SV_Frame (0.1);
+		SV_Frame ();
 
-		oldtime = Sys_DoubleTime () - 0.1;
 		while (1)
 		{
 			if (!isDedicated)
 				Sys_Error("Dedicated was cleared");
-			NET_Sleep(100, false);	
-
-		// find time passed since last cycle
-			newtime = Sys_DoubleTime ();
-			time = newtime - oldtime;
-			oldtime = newtime;
-			
-			SV_Frame (time);
+			NET_Sleep(100, false);				
+			SV_Frame ();
 		}
 		return TRUE;
 	}
@@ -1141,7 +1138,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
 			time = newtime - oldtime;
 			oldtime = newtime;
 			
-			SV_Frame (time);
+			SV_Frame ();
 		}
 		else
 #endif
diff --git a/engine/common/common.c b/engine/common/common.c
index 50fa04d46..ffb496e60 100644
--- a/engine/common/common.c
+++ b/engine/common/common.c
@@ -3046,6 +3046,12 @@ int COM_FOpenFile(char *filename, FILE **file)
 		*file = NULL;
 	return com_filesize;
 }
+int COM_FOpenWriteFile(char *filename, FILE **file)
+{
+	COM_CreatePath(filename);
+	*file = fopen(filename, "wb");
+	return !!*file;
+}
 //int COM_FOpenFile (char *filename, FILE **file) {file_from_pak=0;return COM_FOpenFile2 (filename, file, false);}	//FIXME: TEMPORARY
 
 
diff --git a/engine/common/common.h b/engine/common/common.h
index 04ca85024..b11aba856 100644
--- a/engine/common/common.h
+++ b/engine/common/common.h
@@ -280,6 +280,11 @@ typedef enum {FSLFRT_LENGTH, FSLFRT_DEPTH_OSONLY, FSLFRT_DEPTH_ANYPATH} FSLF_Ret
 int FS_FLocateFile(char *filename, FSLF_ReturnType_e returntype, flocation_t *loc);
 
 int COM_FOpenFile (char *filename, FILE **file);
+int COM_FOpenWriteFile (char *filename, FILE **file);
+
+//#ifdef _MSC_VER	//this is enough to annoy me, without conflicting with other (more bizzare) platforms.
+//#define fopen dont_use_fopen
+//#endif
 
 void COM_CloseFile (FILE *h);
 
diff --git a/engine/common/cvar.c b/engine/common/cvar.c
index cb17ea06b..91ab3cb5a 100644
--- a/engine/common/cvar.c
+++ b/engine/common/cvar.c
@@ -238,7 +238,7 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
 		if (cls.state >= ca_connected)
 		{
 #ifdef Q2CLIENT
-			if (cls.protocol == CP_QUAKE2)	//q2 just resends the lot. Kinda bad...
+			if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3)	//q2 just resends the lot. Kinda bad...
 			{
 				cls.resendinfo = true;
 			}
diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c
index d7075a86e..816cca00f 100644
--- a/engine/common/gl_q2bsp.c
+++ b/engine/common/gl_q2bsp.c
@@ -1893,6 +1893,9 @@ void CModQ3_LoadSubmodels (lump_t *l)
 		}
 		//submodels
 	}
+
+	VectorCopy(map_cmodels[0].mins, loadmodel->mins);
+	VectorCopy(map_cmodels[0].maxs, loadmodel->maxs);
 }
 
 void CModQ3_LoadShaders (lump_t *l, qboolean useshaders)
diff --git a/engine/common/protocol.h b/engine/common/protocol.h
index 5ffb028df..9e15f529c 100644
--- a/engine/common/protocol.h
+++ b/engine/common/protocol.h
@@ -443,6 +443,7 @@ enum clcq2_ops_e
 
 #define U_DPFLAGS (1<<11)
 #define U_TAGINFO (1<<12)
+#define U_LIGHT (1<<13)
 
 #define U_FARMORE (1<<15)
 
@@ -696,6 +697,10 @@ typedef struct entity_state_s
 	qbyte	dpflags;
 	qbyte	solid;
 
+	unsigned short light[4];
+	qbyte lightstyle;
+	qbyte lightpflags;
+
 	unsigned short tagentity;
 	unsigned short tagindex;
 } entity_state_t;
diff --git a/engine/common/qvm.c b/engine/common/qvm.c
index e49533819..1f0b16ee6 100644
--- a/engine/common/qvm.c
+++ b/engine/common/qvm.c
@@ -435,9 +435,6 @@ qvm_t *QVM_Load(const char *name, sys_callex_t syscall)
 
 	qvm->ds_mask--;
 
-
-	qvm->ds_mask=0xFFFFFFFF;								// FIXME: make real mask to fit ds+ss size
-
 // load instructions
 {
 	qbyte *src=raw+header->codeOffset;
@@ -566,9 +563,6 @@ static void inline QVM_Enter(qvm_t *vm, long size)
 {
 	long *fp;
 
-	if (size&3)
-		Con_Printf("QVM_Enter: size&3\n");
-
 	vm->bp-=size;
 	if(vm->bp<vm->len_ds)
 		Sys_Error("VM run time error: out of stack\n");
@@ -587,9 +581,6 @@ static void inline QVM_Return(qvm_t *vm, long size)
 {
 	long *fp;
 
-	if (size&3)
-		Con_Printf("QVM_Return: size&3\n");
-
 	fp=(long*)(vm->ds+vm->bp);
 	vm->bp+=size;
 
@@ -624,13 +615,18 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
 //all stack shifts in this function are referenced through these 2 macros.
 #define POP(t)	qvm->sp+=t;if (qvm->sp > stackstart) Sys_Error("QVM Stack underflow");
 #define PUSH(v) qvm->sp--;if (qvm->sp < stackend) Sys_Error("QVM Stack overflow");*qvm->sp=v
-	register qvm_op_t op=-1;
-	register unsigned long param;
+	qvm_op_t op=-1;
+	unsigned long param;
 
 	long *fp;
 	unsigned long *stackstart;
 	unsigned long *stackend;
 
+	static int recurse = 0;
+
+	if (recurse++)
+		Host_EndGame("QVM recursivly entered\n");
+
 	stackstart	= (unsigned long*)(qvm->ss+qvm->len_ss);
 	stackend	= (unsigned long*)(qvm->ss);
 
@@ -689,6 +685,7 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
 			if (!qvm->pc)
 			{
 				// pick return value from stack
+				recurse--;
 				return qvm->sp[0];
 			}
 			break;
diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c
index d3dbe0e01..5f36bd961 100644
--- a/engine/gl/gl_draw.c
+++ b/engine/gl/gl_draw.c
@@ -1181,6 +1181,9 @@ void GLDraw_Character (int x, int y, unsigned int num)
 	draw_mesh_st[3][0] = fcol;
 	draw_mesh_st[3][1] = frow+size;
 
+	qglEnable(GL_BLEND);
+	qglDisable(GL_ALPHA_TEST);
+
 	if (num&CON_2NDCHARSETTEXT)
 		GL_DrawMesh(&draw_mesh, char_tex2);
 	else
@@ -1440,6 +1443,9 @@ void GLDraw_Pic (int x, int y, mpic_t *pic)
 	draw_mesh_st[3][0] = gl->sl;
 	draw_mesh_st[3][1] = gl->th;
 
+	qglDisable(GL_ALPHA_TEST);
+	qglEnable(GL_BLEND);
+
 	GL_DrawMesh(&draw_mesh, gl->texnum);
 }
 
diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c
index 9a8ecd329..5496bf987 100644
--- a/engine/gl/gl_ppl.c
+++ b/engine/gl/gl_ppl.c
@@ -1824,6 +1824,9 @@ void PPL_DrawEnt(entity_t *e, void *parm)
 	qglEnd();
 	currententity = e;
 
+	qglDepthMask(1);
+	qglDisable(GL_POLYGON_OFFSET_FILL);
+	
 		R_IBrokeTheArrays();
 		R_DrawGAliasModel (currententity);
 
diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c
index 406360638..5eab890bb 100644
--- a/engine/gl/gl_rmain.c
+++ b/engine/gl/gl_rmain.c
@@ -341,7 +341,7 @@ qboolean R_CullSphere (vec3_t org, float radius)
 void R_RotateForEntity (entity_t *e)
 {
 	float m[16];
-	if (e->flags & Q2RF_WEAPONMODEL)
+	if (e->flags & Q2RF_WEAPONMODEL && r_refdef.currentplayernum>=0)
 	{	//rotate to view first
 		m[0] = cl.viewent[r_refdef.currentplayernum].axis[0][0];
 		m[1] = cl.viewent[r_refdef.currentplayernum].axis[0][1];
@@ -800,7 +800,7 @@ void GLR_DrawEntitiesOnList (void)
 		switch (currententity->model->type)
 		{
 		case mod_alias:
-			if (r_refdef.flags & 1 || !cl.worldmodel || cl.worldmodel->fromgame == fg_doom)
+			if (r_refdef.flags & Q2RDF_NOWORLDMODEL || !cl.worldmodel || cl.worldmodel->fromgame == fg_doom)
 				R_DrawGAliasModel (currententity);
 			break;
 		
@@ -1159,7 +1159,7 @@ void GLR_SetupFrame (void)
 	VectorCopy (r_refdef.vieworg, r_origin);
 
 // current viewleaf
-	if (r_refdef.flags & 1)
+	if (r_refdef.flags & Q2RDF_NOWORLDMODEL)
 	{
 	}
 #ifdef Q2BSPS
@@ -1501,7 +1501,7 @@ void R_RenderScene (void)
 	TRACE(("dbg: calling R_SetFrustrum\n"));
 	R_SetFrustum ();
 
-	if (!(r_refdef.flags & 1))
+	if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
 	{
 #ifdef DOOMWADS
 		if (!GLR_DoomWorld ())
@@ -1527,7 +1527,7 @@ void R_RenderScene (void)
 	TRACE(("dbg: calling R_RenderDlights\n"));
 	R_RenderDlights ();
 
-	if (cl.worldmodel)
+	if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
 	{
 		TRACE(("dbg: calling R_DrawParticles\n"));
 		P_DrawParticles ();
@@ -1548,6 +1548,7 @@ R_Clear
 int gldepthfunc = GL_LEQUAL;
 void R_Clear (void)
 {
+	qglDepthMask(1);
 	if (r_mirroralpha.value != 1.0)
 	{
 		if (gl_clear.value && !r_secondaryview)
@@ -1566,7 +1567,7 @@ void R_Clear (void)
 	{
 		static int trickframe;
 
-		if (gl_clear.value && !(r_refdef.flags & 1))
+		if (gl_clear.value && !(r_refdef.flags & Q2RDF_NOWORLDMODEL))
 			qglClear (GL_COLOR_BUFFER_BIT);
 
 		trickframe++;
@@ -1585,7 +1586,7 @@ void R_Clear (void)
 	}
 	else
 	{
-		if (gl_clear.value && !r_secondaryview)
+		if (gl_clear.value && !r_secondaryview && !(r_refdef.flags & Q2RDF_NOWORLDMODEL))
 			qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 		else
 			qglClear (GL_DEPTH_BUFFER_BIT);
@@ -1989,7 +1990,7 @@ void GLR_RenderView (void)
 		return;
 	}
 
-	if (!(r_refdef.flags & 1))
+	if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
 		if (!r_worldentity.model || !cl.worldmodel)
 		{
 			GL_DoSwap();
diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c
index a43f6adcb..69a8fc0ad 100644
--- a/engine/server/pr_cmds.c
+++ b/engine/server/pr_cmds.c
@@ -9486,6 +9486,11 @@ void PR_RegisterFields(void)	//it's just easier to do it this way.
 	fieldfloat(glow_color);
 	fieldfloat(glow_trail);
 
+	fieldvector(color);
+	fieldfloat(light_lev);
+	fieldfloat(style);
+	fieldfloat(pflags);
+
 	//UDC_EXTEFFECT... yuckie
 	PR_RegisterFieldVar(svprogfuncs, ev_float, "fieldcolor", (int)&((entvars_t*)0)->seefcolour, -1);
 	PR_RegisterFieldVar(svprogfuncs, ev_float, "fieldsizex", (int)&((entvars_t*)0)->seefsizex, -1);
diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h
index 8851c5392..e8de95236 100644
--- a/engine/server/progdefs.h
+++ b/engine/server/progdefs.h
@@ -194,6 +194,11 @@ typedef struct entvars_s
 	float	glow_color;
 	float	glow_trail;
 
+	vec3_t	color;
+	float	light_lev;
+	float	style;
+	float	pflags;
+
 	//EXT_DIMENSION_VISIBLE
 	float	dimension_see;
 	float	dimension_seen;
diff --git a/engine/server/savegame.c b/engine/server/savegame.c
index 936357211..b7032fd28 100644
--- a/engine/server/savegame.c
+++ b/engine/server/savegame.c
@@ -490,7 +490,7 @@ qboolean SV_LoadLevelCache(char *level, char *startspot, qboolean ignoreplayers)
 
 	gametype = cache->gametype;
 
-	sprintf (name, "%s/saves/%s", com_gamedir, level);
+	sprintf (name, "saves/%s", level);
 	COM_DefaultExtension (name, ".lvc");
 
 //	Con_TPrintf (STL_LOADGAMEFROM, name);
@@ -519,7 +519,7 @@ qboolean SV_LoadLevelCache(char *level, char *startspot, qboolean ignoreplayers)
 // been used.  The menu calls it before stuffing loadgame command
 //	SCR_BeginLoadingPlaque ();
 
-	f = fopen (name, "rb");
+	COM_FOpenFile(name, &f);
 	if (!f)
 	{
 		Con_TPrintf (STL_ERRORCOULDNTOPEN);
diff --git a/engine/server/server.h b/engine/server/server.h
index cab978ef7..39e280f01 100644
--- a/engine/server/server.h
+++ b/engine/server/server.h
@@ -106,6 +106,7 @@ typedef struct
 	qboolean	csqcdebug;
 
 	double		time;
+	double		starttime;
 	float	physicstime;	//nq clients do so much better with times sent with physics than real.
 	int framenum;
 	
@@ -312,6 +313,13 @@ typedef struct	//merge?
 	int					num_entities;
 	int					first_entity;		// into the circular sv_packet_entities[]
 	int					senttime;			// for ping calculations
+
+
+	int				serverMessageNum;
+	int				serverCommandNum;
+	int				serverTime;		// server time the message is valid for (in msec)
+	int				localTime;
+	int				deltaFrame;
 } q3client_frame_t;
 #endif
 
@@ -863,7 +871,7 @@ extern	FILE		*sv_fraglogfile;
 //
 void VARGS SV_Error (char *error, ...);
 void SV_Shutdown (void);
-void SV_Frame (float time);
+void SV_Frame (void);
 void SV_FinalMessage (char *message);
 void SV_DropClient (client_t *drop);
 struct quakeparms_s;
diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c
index 07daa083d..8639a77a7 100644
--- a/engine/server/sv_ents.c
+++ b/engine/server/sv_ents.c
@@ -527,12 +527,15 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb
 	if (to->glowsize != from->glowsize)
 		to->dpflags |= 4;
 
-	if (to->dpflags != from->dpflags)
+	if (to->dpflags != from->dpflags && protext & PEXT_DPFLAGS)
 		evenmorebits |= U_DPFLAGS;
 
-	if (to->tagentity != from->tagentity || to->tagindex != from->tagindex)
+	if ((to->tagentity != from->tagentity || to->tagindex != from->tagindex) && protext & PEXT_DPFLAGS)
 		evenmorebits |= U_TAGINFO;
 
+	if ((to->light[0] != from->light[0] || to->light[1] != from->light[1] || to->light[2] != from->light[2] || to->light[3] != from->light[3] || to->lightstyle != from->lightstyle || to->lightpflags != from->lightstyle) && protext & PEXT_DPFLAGS)
+		evenmorebits |= U_LIGHT;
+
 	if (evenmorebits&0xff00)
 		evenmorebits |= U_YETMORE;
 	if (evenmorebits&0x00ff)
@@ -622,6 +625,15 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb
 		MSG_WriteShort (msg, to->tagindex);
 	}
 
+	if (evenmorebits & U_LIGHT)
+	{
+		MSG_WriteShort (msg, to->light[0]);
+		MSG_WriteShort (msg, to->light[1]);
+		MSG_WriteShort (msg, to->light[2]);
+		MSG_WriteShort (msg, to->light[3]);
+		MSG_WriteByte (msg, to->lightstyle);
+		MSG_WriteByte (msg, to->lightpflags);
+	}
 }
 
 /*
@@ -826,8 +838,8 @@ void SVDP_EmitEntity(entity_state_t *from, entity_state_t *to, sizebuf_t *msg, q
 		bits |= E5_COLORMAP;
 	if (from->tagentity != to->tagentity || from->tagindex != to->tagindex)
 		bits |= E5_ATTACHMENT;
-//	if (from->light[0] != to->light[0] || o->light[1] != to->light[1] || o->light[2] != to->light[2] || o->light[3] != to->light[3] || o->lightstyle != to->lightstyle || o->lightpflags != to->lightpflags)
-//		bits |= E5_LIGHT;
+	if (from->light[0] != to->light[0] || from->light[1] != to->light[1] || from->light[2] != to->light[2] || from->light[3] != to->light[3] || from->lightstyle != to->lightstyle || from->lightpflags != to->lightpflags)
+		bits |= E5_LIGHT;
 	if (from->glowsize != to->glowsize || from->glowcolour != to->glowcolour)
 		bits |= E5_GLOW;
 //	if (from->colormod[0] != to->colormod[0] || o->colormod[1] != to->colormod[1] || o->colormod[2] != to->colormod[2])
@@ -937,15 +949,15 @@ void SVDP_EmitEntity(entity_state_t *from, entity_state_t *to, sizebuf_t *msg, q
 		MSG_WriteShort(msg, to->tagentity);
 		MSG_WriteByte(msg, to->tagindex);
 	}
-//	if (bits & E5_LIGHT)
-//	{
-//		MSG_WriteShort(msg, to->light[0]);
-//		MSG_WriteShort(msg, to->light[1]);
-//		MSG_WriteShort(msg, to->light[2]);
-//		MSG_WriteShort(msg, to->light[3]);
-//		MSG_WriteByte(msg, to->lightstyle);
-//		MSG_WriteByte(msg, to->lightpflags);
-//	}
+	if (bits & E5_LIGHT)
+	{
+		MSG_WriteShort(msg, to->light[0]);
+		MSG_WriteShort(msg, to->light[1]);
+		MSG_WriteShort(msg, to->light[2]);
+		MSG_WriteShort(msg, to->light[3]);
+		MSG_WriteByte(msg, to->lightstyle);
+		MSG_WriteByte(msg, to->lightpflags);
+	}
 	if (bits & E5_GLOW)
 	{
 		MSG_WriteByte(msg, to->glowsize);
@@ -2646,7 +2658,15 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
 		state->abslight = (int)(ent->v->abslight*255) & 255;
 		state->tagentity = ent->v->tag_entity;
 		state->tagindex = ent->v->tag_index;
-		if ((int)ent->v->flags & FL_CLASS_DEPENDENT && client->playerclass)
+
+		state->light[0] = ent->v->color[0]*255;
+		state->light[1] = ent->v->color[1]*255;
+		state->light[2] = ent->v->color[2]*255;
+		state->light[3] = ent->v->light_lev;
+		state->lightstyle = ent->v->style;
+		state->lightpflags = ent->v->pflags;
+
+		if ((int)ent->v->flags & FL_CLASS_DEPENDENT && client->playerclass)	//hexen2 wierdness.
 		{
 			char modname[MAX_QPATH];
 			Q_strncpyz(modname, sv.model_precache[state->modelindex], sizeof(modname));
diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c
index 978cfc038..b44247994 100644
--- a/engine/server/sv_init.c
+++ b/engine/server/sv_init.c
@@ -635,8 +635,19 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
 
 	Cvar_ApplyLatches(CVAR_LATCH);
 
+//work out the gamespeed
+	sv.gamespeed = sv_gamespeed.value;
+	Info_SetValueForStarKey(svs.info, "*gamespeed", va("%i", (int)(sv.gamespeed*100)), MAX_SERVERINFO_STRING);
+	sv.gamespeed = atof(Info_ValueForKey(svs.info, "*gamespeed"))/100;
+	if (sv.gamespeed < 0.1 || sv.gamespeed == 1)
+	{
+		sv.gamespeed = 1;
+		Info_SetValueForStarKey(svs.info, "*gamespeed", "", MAX_SERVERINFO_STRING);
+	}
+//reset the server time.
 	sv.time = 0.1;	//some progs don't like time starting at 0.
 					//cos of spawn funcs like self.nextthink = time...
+	sv.starttime = Sys_DoubleTime();
 
 	COM_FlushTempoaryPacks();
 
@@ -698,15 +709,6 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
 		Info_SetValueForStarKey(svs.info, "*cheats", "", MAX_SERVERINFO_STRING);
 	}
 
-	sv.gamespeed = sv_gamespeed.value;
-	Info_SetValueForStarKey(svs.info, "*gamespeed", va("%i", (int)(sv.gamespeed*100)), MAX_SERVERINFO_STRING);
-	sv.gamespeed = atof(Info_ValueForKey(svs.info, "*gamespeed"))/100;
-	if (sv.gamespeed < 0.1 || sv.gamespeed == 1)
-	{
-		sv.gamespeed = 1;
-		Info_SetValueForStarKey(svs.info, "*gamespeed", "", MAX_SERVERINFO_STRING);
-	}
-
 	//do we allow csprogs?
 #ifdef PEXT_CSQC
 	file = COM_LoadTempFile("csprogs.dat");
@@ -868,6 +870,11 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
 		}
 		sv.allocated_client_slots = i;
 		break;
+#endif
+#ifdef Q3SERVER
+	case GT_QUAKE3:
+		sv.allocated_client_slots = 32;
+		break;
 #endif
 	}
 
@@ -1069,6 +1076,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
 #endif
 	realtime += 0.1;
 	sv.time += 0.1;
+	sv.starttime -= 0.1;
 	SV_Physics ();
 
 #ifndef SERVERONLY
diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c
index 2ca2d0321..58ee2996a 100644
--- a/engine/server/sv_main.c
+++ b/engine/server/sv_main.c
@@ -2304,7 +2304,7 @@ void SV_WriteIP_f (void)
 
 	Con_Printf ("Writing %s.\n", name);
 
-	f = fopen (name, "wb");
+	COM_FOpenWriteFile(name, &f);
 	if (!f)
 	{
 		Con_Printf ("Couldn't open %s\n", name);
@@ -2692,10 +2692,11 @@ SV_Frame
 
 ==================
 */
-void SV_Frame (float time)
+void SV_Frame (void)
 {
 	extern cvar_t pr_imitatemvdsv;
 	static double	start, end;
+	float oldtime;
 
 	start = Sys_DoubleTime ();
 	svs.stats.idle += start - end;
@@ -2708,15 +2709,26 @@ void SV_Frame (float time)
 		sv.gamespeed = 1;
 
 // decide the simulation time
-	if (!sv.paused) {
+	{
+		oldtime = sv.time;
+		sv.time = (Sys_DoubleTime() - sv.starttime)*sv.gamespeed;
+		if (sv.time < oldtime)
+			sv.time = oldtime;	//urm
+
+		if (sv.paused)
+		{
+			sv.starttime += sv.time - oldtime;	//move the offset
+			sv.time = oldtime;	//and keep time as it was.
+		}
+
 #ifndef SERVERONLY
 		if (isDedicated)
 #endif
-			realtime += time;
+			realtime += sv.time - oldtime;
 
-		time *= sv.gamespeed;
-		sv.time += time;
 	}
+
+
 #ifdef IWEB_H__
 	IWebRun();
 #endif
@@ -3074,6 +3086,9 @@ void SV_InitLocal (void)
 #ifdef PEXT_CSQC
 	svs.fteprotocolextensions |= PEXT_CSQC;
 #endif
+#ifdef PEXT_DPFLAGS
+	svs.fteprotocolextensions |= PEXT_DPFLAGS;
+#endif
 
 //	if (svs.protocolextensions)
 //		Info_SetValueForStarKey (svs.info, "*"DISTRIBUTION"_ext", va("%x", svs.protocolextensions), MAX_SERVERINFO_STRING);
diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c
index 1182120fb..f35316c28 100644
--- a/engine/server/sv_user.c
+++ b/engine/server/sv_user.c
@@ -3919,7 +3919,6 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
 	if (progstype == PROG_H2)
 		sv_player->v->light_level = 128;	//hmm... HACK!!!
 
-	sv_player->v->Version++;
 	sv_player->v->button0 = ucmd->buttons & 1;
 	sv_player->v->button2 = (ucmd->buttons >> 1) & 1;
 	if (pr_allowbutton1.value)	//many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.