diff -wrubN quake3_1.32b/code/client/cl_console.c dfengine_1.08_src/code/client/cl_console.c
--- quake3_1.32b/code/client/cl_console.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/client/cl_console.c	2009-12-31 16:09:29.000000000 +0100
@@ -23,13 +23,14 @@
 
 #include "client.h"
 
+#include <pcre.h>	// Cgg
 
 int g_console_field_width = 78;
 
 
 #define	NUM_CON_TIMES 4
 
-#define		CON_TEXTSIZE	32768
+#define		CON_TEXTSIZE	0x10000	// Cgg - doubled
 typedef struct {
 	qboolean	initialized;
 
@@ -45,7 +46,7 @@
 
 	float	displayFrac;	// aproaches finalFrac at scr_conspeed
 	float	finalFrac;		// 0.0 to 1.0 lines of console to display
-
+	float	userFrac;		// 0.0 to 1.0 - for user Configurations. Don't want to mess with finalFrac - marky
 	int		vislines;		// in scanlines
 
 	int		times[NUM_CON_TIMES];	// cls.realtime time the line was generated
@@ -59,6 +60,15 @@
 
 cvar_t		*con_conspeed;
 cvar_t		*con_notifytime;
+// Cgg
+cvar_t		*con_useshader;
+cvar_t		*con_opacity;
+cvar_t		*con_rgb;
+
+#define MAX_CON_FILTERS 20
+cvar_t *con_filters[MAX_CON_FILTERS];
+pcre *con_filters_compiled[MAX_CON_FILTERS];
+// !Cgg
 
 #define	DEFAULT_CONSOLE_WIDTH	78
 
@@ -67,6 +77,15 @@
 
 /*
 ================
+Con_ShowPCREVersion_f (Cgg - pcre support)
+================
+*/
+static void Con_ShowPCREVersion_f(void) {
+	Com_Printf("%s\n", pcre_version());
+}
+
+/*
+================
 Con_ToggleConsole_f
 ================
 */
@@ -82,6 +101,8 @@
 
 	Con_ClearNotify ();
 	cls.keyCatchers ^= KEYCATCH_CONSOLE;
+
+	in_keyboardShortcuts->modified = qtrue; // drakkar
 }
 
 /*
@@ -93,7 +114,10 @@
 	chat_playerNum = -1;
 	chat_team = qfalse;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 30;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -7;	// -7: "say: " + padding
+	//chatField.widthInChars = 30;
+	// !Cgg
 
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
@@ -107,7 +131,10 @@
 	chat_playerNum = -1;
 	chat_team = qtrue;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 25;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -12; // -12: "say_team: " + padding
+//	chatField.widthInChars = 25;
+	// !Cgg
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
 
@@ -124,7 +151,10 @@
 	}
 	chat_team = qfalse;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 30;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -7;	// -7: "say: " + padding
+//	chatField.widthInChars = 30;
+	// !Cgg
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
 
@@ -141,7 +171,10 @@
 	}
 	chat_team = qfalse;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 30;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -7; // -7: "say: " + padding
+//	chatField.widthInChars = 30;
+	// !Cgg
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
 
@@ -250,7 +283,7 @@
 	int		i, j, width, oldwidth, oldtotallines, numlines, numchars;
 	MAC_STATIC short	tbuf[CON_TEXTSIZE];
 
-	width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2;
+	width = (cls.glconfig.vidWidth / SMALLCHAR_WIDTH) - 2;	// Cgg - was SCREEN_WIDTH
 
 	if (width == con.linewidth)
 		return;
@@ -315,6 +348,15 @@
 	con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
 	con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
 
+	// Cgg
+	con_useshader = Cvar_Get("con_useshader", "0", CVAR_ARCHIVE);
+	con_opacity = Cvar_Get("con_opacity", "0.95", CVAR_ARCHIVE);
+	con_rgb = Cvar_Get("con_rgb", ".05 .05 .1", CVAR_ARCHIVE);
+	for (i=0; i<MAX_CON_FILTERS; i++) {
+		con_filters[i] = Cvar_Get(va("con_filter%i", i), "", CVAR_ARCHIVE);
+	}
+	// !Cgg
+
 	Field_Clear( &g_consoleField );
 	g_consoleField.widthInChars = g_console_field_width;
 	for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
@@ -329,6 +371,7 @@
 	Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
 	Cmd_AddCommand ("clear", Con_Clear_f);
 	Cmd_AddCommand ("condump", Con_Dump_f);
+	Cmd_AddCommand ("pcre_version", Con_ShowPCREVersion_f );	// Cgg
 }
 
 
@@ -340,6 +383,32 @@
 void Con_Linefeed (qboolean skipnotify)
 {
 	int		i;
+	char txt[MAXPRINTMSG];
+	pcre **re;
+	int ovector[30];
+	char ch;
+	qboolean copy;
+
+	// Cgg
+	if (con.linewidth < sizeof(txt)) {
+		for (i=con.linewidth-1,copy=qfalse; i>=0; i--) {
+			ch = con.text[(con.current%con.totallines)*con.linewidth+i] &0xff;
+			if (ch != ' ') {
+				copy = qtrue;
+			}
+			txt[i] = (copy) ? ch : 0;
+		}
+		for (re=con_filters_compiled; re-con_filters_compiled<MAX_CON_FILTERS; re++) {
+			if (*re && pcre_exec(*re, NULL, txt, strlen(txt), 0, 0, ovector, 30) > 0) {
+				con.x = 0;
+				for(i=0; i<con.linewidth; i++) {
+					con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
+				}
+				return;
+			}
+		}
+	}
+	// !Cgg
 
 	// mark time for transparent overlay
 	if (con.current >= 0)
@@ -367,12 +436,14 @@
 If no console is visible, the text will appear at the top of the game window
 ================
 */
+#define Q_RAW_ESCAPE 1	// Cgg: see below
 void CL_ConsolePrint( char *txt ) {
 	int		y;
 	int		c, l;
 	int		color;
 	qboolean skipnotify = qfalse;		// NERVE - SMF
 	int prev;							// NERVE - SMF
+	char raw;	// Cgg: Q_RAW_ESCAPE char stops color sequences from being interpreted.
 
 	// TTimo - prefix for text that shows up in console but not in notify
 	// backported from RTCW
@@ -398,12 +469,20 @@
 
 	color = ColorIndex(COLOR_WHITE);
 
+	raw = 0;
 	while ( (c = *txt) != 0 ) {
+		if (!raw) {
 		if ( Q_IsColorString( txt ) ) {
 			color = ColorIndex( *(txt+1) );
 			txt += 2;
 			continue;
 		}
+			// Cgg - repeated escape codes (^^) were broken
+			if (*txt == Q_COLOR_ESCAPE && *(txt+1) == Q_COLOR_ESCAPE) {
+				txt++;
+			}
+			// !Cgg
+		}
 
 		// count word length
 		for (l=0 ; l< con.linewidth ; l++) {
@@ -423,7 +502,11 @@
 
 		switch (c)
 		{
+		case Q_RAW_ESCAPE:
+			raw = raw^1;
+			break;
 		case '\n':
+			raw = 0;
 			Con_Linefeed (skipnotify);
 			break;
 		case '\r':
@@ -532,8 +615,8 @@
 			if ( ( text[x] & 0xff ) == ' ' ) {
 				continue;
 			}
-			if ( ( (text[x]>>8)&7 ) != currentColor ) {
-				currentColor = (text[x]>>8)&7;
+			if ( ( ((text[x]>>8)&15)%10 ) != currentColor ) {
+				currentColor = ((text[x]>>8)&15)%10;
 				re.SetColor( g_color_table[currentColor] );
 			}
 			SCR_DrawSmallChar( cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff );
@@ -553,17 +636,28 @@
 	{
 		if (chat_team)
 		{
-			SCR_DrawBigString (8, v, "say_team:", 1.0f );
+			// Cgg
+			SCR_DrawSmallStringExt(8, v, "say_team:", colorWhite, qfalse, qfalse);
+			//SCR_DrawBigString (8, v, "say_team:", 1.0f );
+			// !Cgg
 			skip = 11;
 		}
 		else
 		{
-			SCR_DrawBigString (8, v, "say:", 1.0f );
-			skip = 5;
+			// Cgg
+			SCR_DrawSmallStringExt(8, v, "say:", colorWhite, qfalse, qfalse);
+			skip = 6;
+			//skip = 5;
+			//SCR_DrawBigString (8, v, "say:", 1.0f );
+			// !Cgg
 		}
 
-		Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
-			SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue );
+		// Cgg
+		Field_Draw(&chatField,  skip * TINYCHAR_WIDTH, v,
+			SCREEN_WIDTH - ( skip + 1 ) * TINYCHAR_WIDTH, qtrue );
+		//Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
+		//	SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue );
+		// !Cgg
 
 		v += BIGCHAR_HEIGHT;
 	}
@@ -585,7 +679,6 @@
 	int				lines;
 //	qhandle_t		conShader;
 	int				currentColor;
-	vec4_t			color;
 
 	lines = cls.glconfig.vidHeight * frac;
 	if (lines <= 0)
@@ -599,24 +692,31 @@
 	SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
 
 	// draw the background
-	y = frac * SCREEN_HEIGHT - 2;
+	y = frac * SCREEN_HEIGHT - 1;	// Cgg - was 2
 	if ( y < 1 ) {
 		y = 0;
 	}
 	else {
+		// Cgg
+		if (con_useshader->integer) {
 		SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
+		} else {
+			vec4_t color;
+			char *c = con_rgb->string;
+			color[0] = atof(COM_Parse(&c));
+			color[1] = atof(COM_Parse(&c));
+			color[2] = atof(COM_Parse(&c));
+			color[3] = con_opacity->value;
+			SCR_FillRect( 0, 0, SCREEN_WIDTH, y, color );
+		}
+		// !Cgg
 	}
 
-	color[0] = 1;
-	color[1] = 0;
-	color[2] = 0;
-	color[3] = 1;
-	SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );
-
+	SCR_FillRect( 0, y, SCREEN_WIDTH, 1, colorOrange );	// Cgg - orange & 1px instead of 2
 
 	// draw the version number
 
-	re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+	re.SetColor( g_color_table[ColorIndex(COLOR_ORANGE)] );	// Cgg - orange
 
 	i = strlen( Q3_VERSION );
 
@@ -639,7 +739,7 @@
 	if (con.display != con.current)
 	{
 	// draw arrows to show the buffer is backscrolled
-		re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+		re.SetColor( g_color_table[ColorIndex(COLOR_ORANGE)] );	// Cgg - orange
 		for (x=0 ; x<con.linewidth ; x+=4)
 			SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, '^' );
 		y -= SMALLCHAR_HEIGHT;
@@ -671,8 +771,8 @@
 				continue;
 			}
 
-			if ( ( (text[x]>>8)&7 ) != currentColor ) {
-				currentColor = (text[x]>>8)&7;
+			if ( ( ((text[x]>>8)&15)%10 ) != currentColor ) {
+				currentColor = ((text[x]>>8)&15)%10;
 				re.SetColor( g_color_table[currentColor] );
 			}
 			SCR_DrawSmallChar(  con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff );
@@ -724,9 +824,34 @@
 ==================
 */
 void Con_RunConsole (void) {
+	// Cgg - check for updated con_filters
+	cvar_t **cvar;
+	pcre **re;
+	const char *errptr;
+	int erroffset;
+	for (cvar=con_filters; cvar-con_filters<MAX_CON_FILTERS; cvar++) {
+		if (!*cvar || !(*cvar)->modified) {
+			continue;
+		}
+		re = con_filters_compiled+(cvar-con_filters);
+		(*cvar)->modified = qfalse;
+		if (!strlen((*cvar)->string)) {
+			*re = NULL;
+			continue;
+		}
+		*re = pcre_compile((*cvar)->string, 0, &errptr, &erroffset, NULL);
+		if (!*re) {
+			Com_Printf("Failed to compile %c%s\n", Q_RAW_ESCAPE, (*cvar)->string);
+			Com_Printf(va("%c%%%ic %%s\n", Q_RAW_ESCAPE, erroffset+19), '^', errptr);
+			Cvar_Set((*cvar)->name, "");
+			(*cvar)->modified = qfalse;
+		}
+	}
+	// !Cgg
+
 	// decide on the destination height of the console
 	if ( cls.keyCatchers & KEYCATCH_CONSOLE )
-		con.finalFrac = 0.5;		// half screen
+		con.finalFrac = con.userFrac;	// marky
 	else
 		con.finalFrac = 0;				// none visible
 	
@@ -747,6 +872,25 @@
 
 }
 
+// marky
+/*
+==================
+Con_SetFrac
+==================
+*/
+void Con_SetFrac(const float conFrac)
+{
+	// clamp the cvar value
+	if (conFrac < .1f) {	// don't let the console be hidden
+		con.userFrac = .1f;
+	} else if (conFrac > 1.0f) {
+		con.userFrac = 1.0f;
+	} else {
+		con.userFrac = conFrac;
+	}
+}
+// !marky
+
 
 void Con_PageUp( void ) {
 	con.display -= 2;
@@ -783,4 +927,6 @@
 	cls.keyCatchers &= ~KEYCATCH_CONSOLE;
 	con.finalFrac = 0;				// none visible
 	con.displayFrac = 0;
+
+	in_keyboardShortcuts->modified = qtrue; // drakkar
 }
diff -wrubN quake3_1.32b/code/client/cl_download.c dfengine_1.08_src/code/client/cl_download.c
--- quake3_1.32b/code/client/cl_download.c	1970-01-01 01:00:00.000000000 +0100
+++ dfengine_1.08_src/code/client/cl_download.c	2010-01-20 13:22:16.000000000 +0100
@@ -0,0 +1,685 @@
+/*
+===========================================================================
+Copyright (C) 2009 Cyril Gantin
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+
+Integration of libcurl for requesting maps from an online repository.
+
+Usage:
+  \download <mapname>     - blocking download ( hold ESC to abort )
+  \download <mapname> &   - background download
+  \download -             - abort current background download
+  \download               - show help or background download progress
+
+Cvar dl_source defines the url from which to query maps, eg: http://someserver/somescript.php?q=%m
+The %m token is replaced with the actual map name in the query.
+
+The server MUST return an appropriate content-type. Accepted content-type values are either application/zip
+or application/octet-stream. Other content-type values will be treated as errors or queries that didn't
+yield results.
+
+The server MAY return a content-disposition header with the actual name of the pk3 file. In the absence
+of a content-disposition header, the client will write the pack to a default <mapname>.pk3 location. The
+filename MUST have a pk3 extension. The filename MUST NOT have directory path information - slashes (/),
+backslashes (\) and colons (:) are not accepted. Finally the filename MUST consist of us-ascii characters
+only (chars 32 to 126, included). A filename that doesn't comply to these specifications will raise an
+error and abort the transfer.
+
+The server MAY redirect the query to another url. Multiple redirections are permitted - limit depends on
+libcurl's default settings. The end query MUST return a "200 OK" http status code.
+
+It is desirable that the server returns a content-length header with the size of the pk3 file.
+
+The server MAY return a custom x-dfengine-motd header. Its value is a string that MUST NOT exceed 127
+chars. The x-dfengine-motd string will be displayed after the download is complete. This is the place
+where you take credits for setting up a server. :)
+
+Downloaded files are written to the current gamedir of the home directory - eg. C:\quake3\mymod\ in
+windows; ~/.q3a/mymod/ in linux. Name collision with an existing pk3 file will result in a failure and
+be left to the user to sort out.
+
+*/
+
+#include <curl/curl.h>
+#include "client.h"
+
+static cvar_t *dl_verbose;	// 1: show http headers; 2: http headers +curl debug info
+static cvar_t *dl_showprogress;	// 0: do not show; 1: show console progress; 2: show progress in one line
+static cvar_t *dl_showmotd;	// show server message
+static cvar_t *dl_source;	// url to query maps from; %m token will be replaced by mapname
+static cvar_t *dl_usebaseq3;	// whether to download pk3 files in baseq3 (default is off)
+
+static qboolean curl_initialized;
+static char useragent[256];
+static CURL *curl = NULL;
+static CURLM *curlm = NULL;
+static fileHandle_t f = 0;
+static char path[MAX_OSPATH];
+static char dl_error[1024];	// if set, will be used in place of libcurl's error message.
+static char motd[128];
+
+
+static size_t Curl_WriteCallback_f(void *ptr, size_t size, size_t nmemb, void *stream) {
+	if (!f) {
+		char dir[MAX_OSPATH];
+		char *c;
+		// make sure Content-Type is either "application/octet-stream" or "application/zip".
+		if (curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &c) != CURLE_OK
+				|| !c
+				|| (stricmp(c, "application/octet-stream")
+					&& stricmp(c, "application/zip"))) {
+			Q_strncpyz(dl_error, "No pk3 returned - requested map is probably unknown.", sizeof(dl_error));
+			return 0;
+		}
+		// make sure the path doesn't have directory information.
+		for (c=path; *c; c++) {
+			if (*c == '\\' || *c == '/' || *c == ':') {
+				Com_sprintf(dl_error, sizeof(dl_error), "Destination filename \"%s\" is not valid.", path);
+				return 0;
+			}
+		}
+		// make sure the file has an appropriate extension.
+		c = path +strlen(path) -4;
+		if (c <= path || strcmp(c, ".pk3")) {
+			Com_sprintf(dl_error, sizeof(dl_error), "Returned file \"%s\" has wrong extension.", path);
+			return 0;
+		}
+		// make out the directory in which to place the file
+		Q_strncpyz(dir, (dl_usebaseq3->integer)?"baseq3":FS_GetGameDir(), sizeof(dir));
+		if (strlen(path) +strlen(dir) +1 >= sizeof(path)) {
+			Com_sprintf(dl_error, sizeof(dl_error), "Returned filename is too large.");
+			return 0;
+		}
+		Com_sprintf(path, sizeof(path), "%s/%s", dir, path);
+		// in case of a name collision, just fail - leave it to the user to sort out.
+		if (FS_SV_FileExists(path)) {
+			Com_sprintf(dl_error, sizeof(dl_error), "Failed to download \"%s\", a pk3 by that name exists locally.", path);
+			return 0;
+		}
+		// change the extension to .tmp - it will be changed back once the download is complete.
+		c = path +strlen(path) -4;
+		strcpy(c, ".tmp"); 
+
+		// FS should write the file in the appropriate gamedir and catch unsanitary paths.
+		f = FS_SV_FOpenFileWrite(path);
+		if (!f) {
+			Com_sprintf(dl_error, sizeof(dl_error), "Failed to open \"%s\" for writing.\n", path);
+			return 0;
+		}
+		Com_Printf("Writing to: %s\n", path);
+	}
+	return FS_Write(ptr, size*nmemb, f);
+}
+
+static size_t Curl_HeaderCallback_f(void *ptr, size_t size, size_t nmemb, void *stream) {
+	char buf[1024];
+	char *c;
+
+	// make a copy and remove the trailing crlf chars.
+	if (size*nmemb >= sizeof(buf)) {
+		Q_strncpyz(dl_error, "Curl_HeaderCallback_f() overflow.", sizeof(dl_error));
+		return (size_t)-1;
+	}
+	Q_strncpyz(buf, ptr, size*nmemb+1);
+	c = buf +strlen(buf)-1;
+	while (c>buf && (*c == '\r' || *c == '\n')) {
+		*(c--) = 0;
+	}
+
+	// make sure it's not empty.
+	if (c <= buf) {
+		return size*nmemb;
+	}
+
+	// verbose output
+	if (dl_verbose->integer > 0) {
+		Com_Printf("< %s\n", buf);
+	}
+	/**
+	 * Check whether this is a content-disposition header.
+	 * Apparently RFC2183 has precise rules for the presentation of the filename attribute.
+	 * No one seems to respect those, though.
+	 * Accepted presentations:
+	 *	filename="somefile.pk3"
+	 *	filename='somefile.pk3'
+	 *	filename=somefile.pk3
+	 * Quoted strings won't support escaping (eg. "some\"file.pk3").
+	 * Malformed quoted strings that miss the trailing quotation mark will pass.
+	 * Only us-ascii chars are accepted.
+	 * The actual filename will be validated later, when the transfer is started.
+	 */
+	if (!strncasecmp(buf, "content-disposition:", 20)) {
+		const char *c = strstr(buf, "filename=") +9;
+		if (c != (char*)9) {
+			const char *e;
+			char token=0;
+			if (*c == '"' || *c == '\'') {
+				token = *c++;
+			}
+			for (e=c; *e && *e != token; e++) {
+				if (*e<32 || *e > 126) {
+					Q_strncpyz(dl_error, "Server returned an invalid filename.", sizeof(dl_error));
+					return (size_t)-1;
+				}
+			}
+			if (e == c || e-c >= sizeof(path)) {
+				Q_strncpyz(dl_error, "Server returned an invalid filename.", sizeof(dl_error));
+				return (size_t)-1;
+			}
+			Q_strncpyz(path, c, e-c+1);	// +1 makes room for the trailing \0
+		}
+	}
+
+	// catch x-dfengine-motd headers
+	if (!strncasecmp(buf, "x-dfengine-motd: ", 17)) {
+		if (strlen(buf) >= 17+sizeof(motd)) {
+			if (dl_showmotd->integer) {
+				Com_Printf("Warning: server motd string too large.\n");
+			}
+		} else {
+			Q_strncpyz(motd, buf+17, sizeof(motd));
+			Cvar_Set( "cl_downloadMotd", motd );
+		}
+	}
+	return size*nmemb;
+}
+
+static size_t Curl_VerboseCallback_f(CURL *curl, curl_infotype type, char *data, size_t size, void *userptr) {
+	char buf[1024];
+	char *c, *l;
+
+	if ((type != CURLINFO_HEADER_OUT || dl_verbose->integer < 1)
+			&& (type != CURLINFO_TEXT || dl_verbose->integer < 2)) {
+		return 0;
+	}
+	if (size >= sizeof(buf)) {
+		Com_Printf("Curl_VerboseCallback_f() warning: overflow.\n");
+		return 0;
+	}
+	Q_strncpyz(buf, data, size+1);	// +1 makes room for the trailing \0
+	if (type == CURLINFO_HEADER_OUT) {
+		for (l=c=buf; c-buf<size; c++) {
+			// header lines should have linefeeds.
+			if (*c == '\n' || *c == '\r') {
+				*c = 0;
+				if (c>l) {
+					Com_Printf("> %s\n", l);
+				}
+				l = c+1;
+			}
+		}
+		return 0;
+	}
+	// CURLINFO_TEXT (has its own linefeeds)
+	Com_Printf("%s", buf);	// Com_Printf(buf) would result in random output/segfault if buf has % chars.
+	return 0;
+}
+
+/**
+ * This callback is called on regular intervals, whether data is being transferred or not.
+ */
+static int Curl_ProgressCallback_f(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
+	
+	if( curlm ) // dont print progress in console if nonblocking download
+	{
+		DL_Info( qfalse );
+	}
+	else // print progress if blocking download
+	{
+		DL_Info( qtrue );
+
+		// pump events and refresh screen
+		Com_EventLoop();
+		SCR_UpdateScreen();
+		if (Key_IsDown(K_ESCAPE)) {
+			Q_strncpyz(dl_error, "Download aborted.", sizeof(dl_error));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+
+static void Curl_ShowVersion_f(void) {
+	Com_Printf("%s\n", curl_version());
+}
+
+
+
+static void Curl_Download_f( void )
+{
+	qboolean nonblocking;
+	int state;
+
+	// interrupt download: \download -
+	if( Cmd_Argc() >= 2 && !Q_strncmp( "-", Cmd_Argv(1), 1 ) )
+	{
+		if( DL_Active() )		
+			DL_Interrupt();
+		else
+			Com_Printf( "No download in progress.\n" );
+		return;
+	}
+
+	if( DL_Active() )
+	{
+		Com_Printf( "Already downloading map '%s'.\n", Cvar_VariableString("cl_downloadName") );
+		DL_Info( qtrue );
+		return;
+	}
+
+	// help: \download
+	if( Cmd_Argc() < 2 )
+	{
+		Com_Printf( "How to use:\n"
+					" \\download <mapname>     - blocking download ( hold ESC to abort )\n"
+					" \\download <mapname> &   - background download\n"
+					" \\download -             - abort current background download\n"
+					" \\download               - show help or background download progress\n"
+		);
+		return;
+	}
+
+	// non blocking download: \download <mapname> &
+	nonblocking = ( Cmd_Argc() >= 3 ) && ( !Q_strncmp( "&", Cmd_Argv(2), 1 ) );
+	
+	// initialize download
+	state = DL_Begin( Cmd_Argv(1), nonblocking );
+	if( state != 1 ) return;
+
+	// if blocking, download all file now
+	if( !nonblocking ) DL_Continue();
+}
+
+
+
+
+
+//
+// Interface
+//
+void DL_Init() {
+	if (!curl_global_init(CURL_GLOBAL_ALL)) {
+		char *c;
+		Cmd_AddCommand("curl_version", Curl_ShowVersion_f);
+		Cmd_AddCommand("download", Curl_Download_f);
+		curl_initialized = qtrue;
+
+		// set user-agent, something along the lines of "dfengine/1.## (libcurl/#.##.# linked libs...)"
+		Q_strncpyz(useragent, Q3_VERSION, sizeof(useragent));
+		for (c=useragent; *c; c++) {
+			if (*c == ' ') *c = '/';
+		}
+		Com_sprintf(useragent, sizeof(useragent), "%s (%s) ", useragent, curl_version());
+	} else {
+		Com_Printf("Failed to initialize libcurl.\n");
+	}
+	dl_verbose = Cvar_Get("dl_verbose", "0", 0);
+	dl_source = Cvar_Get("dl_source", "http://q3a.ath.cx/getpk3bymapname.php/%m", CVAR_ARCHIVE);
+	dl_showprogress = Cvar_Get("dl_showprogress", "1", CVAR_ARCHIVE);
+	dl_showmotd = Cvar_Get("dl_showmotd", "1", CVAR_ARCHIVE);
+	dl_usebaseq3 = Cvar_Get("dl_usebaseq3", "0", CVAR_ARCHIVE);
+}
+
+// 0 : no active,  1 : active blocking,  2 : active nonblocking
+int DL_Active() {
+	if( curlm && curl ) return 2;
+	if( curl ) return 1;
+	return 0;
+}
+
+// the engine might be going dedicated, remove client commands
+void DL_Shutdown() {
+	if (curl_initialized) {
+		if (curlm) {
+			curl_multi_cleanup(curlm);
+			curlm = NULL;
+		}
+		if (curl) {
+			curl_easy_cleanup(curl);
+			curl = NULL;
+		}
+		if (f) {
+			FS_FCloseFile(f);
+			f = 0;
+		}
+		curl_global_cleanup();
+		curl_initialized = qfalse;
+		Cmd_RemoveCommand("curl_version");
+		Cmd_RemoveCommand("download");
+	}
+}
+
+
+
+// -1 : error,  0 : map already exists,  1 : ok
+int DL_Begin( const char *map, qboolean nonblocking )
+{
+	char url[1024];
+	CURLMcode resm;
+	char *c;
+
+	if( DL_Active() ) {
+		Com_Printf("Already downloading map '%s'.\n", Cvar_VariableString("cl_downloadName") );
+		return -1;
+	}
+
+	if (FS_FileIsInPAK(va("maps/%s.bsp", map), NULL) != -1) {
+		Com_Printf("Map already exists locally.\n");
+		return 0;
+	}
+	if (strncasecmp(dl_source->string, "http://", 7)) {
+		if (strstr(dl_source->string, "://")) {
+			Com_Printf("Invalid dl_source.\n");
+			return -1;
+		}
+		Cvar_Set("dl_source", va("http://%s", dl_source->string));
+	}
+	if ((c = strstr(dl_source->string, "%m")) == 0) {
+		Com_Printf("Cvar dl_source is missing a %%m token.\n");
+		return -1;
+	}
+	if (strlen(dl_source->string) -2 +strlen(map) >= sizeof(url)) {
+		Com_Printf("Cvar dl_source too large.\n");
+		return -1;
+	}
+
+	Q_strncpyz(url, dl_source->string, c-dl_source->string +1);	// +1 makes room for the trailing 0
+	Com_sprintf(url, sizeof(url), "%s%s%s", url, map, c+2);
+
+	// set a default destination filename; Content-Disposition headers will override.
+	Com_sprintf(path, sizeof(path), "%s.pk3", map);
+
+	curl = curl_easy_init();
+	if (!curl) {
+		Com_Printf("Download failed to initialize.\n");
+		return -1;
+	}
+
+	*dl_error = 0;
+	*motd = 0;
+	curl_easy_setopt(curl, CURLOPT_URL, url);
+	curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent);
+	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+	curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);	// fail if http returns an error code
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Curl_WriteCallback_f);
+	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Curl_HeaderCallback_f);
+	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+	curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, Curl_VerboseCallback_f);
+	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Curl_ProgressCallback_f);
+	//curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)(4*1024) ); // 4 KB/s for testing timeouts
+
+	if( nonblocking )
+	{
+		curlm = curl_multi_init();
+		if( !curlm )
+		{
+			curl_easy_cleanup( curl );
+			curl = NULL;
+			Com_Printf("Download failed to initialize ( nonblocking ).\n");
+			return -1;
+		}
+		resm = curl_multi_add_handle( curlm, curl );
+		if( resm != CURLM_OK )
+		{
+			curl_multi_cleanup( curlm );
+			curl_easy_cleanup( curl );
+			curlm = NULL;
+			curl = NULL;
+			Com_Printf("Download failed to initialize ( nonblocking ).\n");
+			return -1;
+		}	
+	}
+
+	Com_Printf("Attempting download: %s\n", url);
+
+	Cvar_Set( "cl_downloadName", map );  // show the ui download progress screen
+	Cvar_SetValue( "cl_downloadSize", 0 );
+	Cvar_SetValue( "cl_downloadCount", 0 );
+	Cvar_SetValue( "cl_downloadTime", cls.realtime ); // download start time offset
+
+	return 1;
+}
+
+
+
+void DL_End( CURLcode res, CURLMcode resm )
+{
+	CURLMsg *msg;
+	int msgs;
+
+	if( dl_verbose->integer == 0 && dl_showprogress->integer == 2 && !curlm )
+		Com_Printf( "\n" );
+	
+	if( curlm )
+	{	
+		// res = final download result
+		while( msg = curl_multi_info_read( curlm, &msgs ) )
+		{
+			if( msg->msg != CURLMSG_DONE )
+			{
+				if( dl_error[0] == '\0' )
+					Q_strncpyz( dl_error, "Download Interrupted.", sizeof(dl_error) );
+			}
+			else if( msg->easy_handle == curl )
+			{
+				if( msg->data.result != CURLE_OK );
+					res = msg->data.result;
+			}
+			else
+			{
+				Com_Printf( "Invalid cURL handle.\n" );
+			}
+		}
+
+		curl_multi_cleanup( curlm );
+		curlm = NULL;		
+	}
+
+	if( curl )
+	{
+		curl_easy_cleanup( curl );
+		curl = NULL;
+	}
+
+	// get possible error messages
+	if( !*dl_error && res != CURLE_OK )
+		Q_strncpyz( dl_error, curl_easy_strerror(res), sizeof(dl_error) );
+	if( !*dl_error && resm != CURLM_OK )
+		Q_strncpyz( dl_error, curl_multi_strerror(resm), sizeof(dl_error) );
+	if( !*dl_error && !f )
+		Q_strncpyz( dl_error, "File is not opened.", sizeof(dl_error) );
+
+	if (f) {
+		FS_FCloseFile(f);
+		f = 0;
+		if (!*dl_error) {	// download succeeded
+			char dest[MAX_OSPATH];
+			Com_Printf("Download complete, restarting filesystem.\n");
+			Q_strncpyz(dest, path, strlen(path)-3);	// -4 +1 for the trailing \0
+			Q_strcat(dest, sizeof(dest), ".pk3");
+			if (!FS_SV_FileExists(dest)) {
+				FS_SV_Rename(path, dest);
+				FS_Restart(clc.checksumFeed);
+				if (dl_showmotd->integer && *motd) {
+					Com_Printf("Server motd: %s\n", motd);
+				}
+			} else {
+				// normally such errors should be caught upon starting the transfer. Anyway better do
+				// it here again - the filesystem might have changed, plus this may help contain some
+				// bugs / exploitable flaws in the code.
+				Com_Printf("Failed to copy downloaded file to its location - file already exists.\n");
+				FS_SV_RemoveFile(path);
+			}
+		} else {
+			FS_SV_RemoveFile(path);
+		}
+	}
+
+	Cvar_Set( "cl_downloadName", "" );  // hide the ui downloading screen
+	Cvar_SetValue( "cl_downloadSize", 0 );
+	Cvar_SetValue( "cl_downloadCount", 0 );
+	Cvar_SetValue( "cl_downloadTime", 0 );
+	Cvar_Set( "cl_downloadMotd", "" );
+
+	if( *dl_error )
+	{
+		if( cls.state == CA_CONNECTED )
+			Com_Error( ERR_DROP, "%s\n", dl_error ); // download error while connecting, can not continue loading
+		else
+			Com_Printf( "%s\n", dl_error ); // download error while in game, do not disconnect
+
+		*dl_error = '\0';
+	}
+	else
+	{
+		// download completed, request new gamestate to check possible new map if we are not already in game
+		if( cls.state == CA_CONNECTED )
+			CL_AddReliableCommand( "donedl" ); // get new gamestate info from server
+	}
+}
+
+
+
+// -1 : error,  0 : done,  1 : continue
+int DL_Continue( void )
+{
+	CURLcode  res  = CURLE_OK;
+	CURLMcode resm = CURLM_OK;
+	int running = 1;
+	int state = -1;
+
+	if( !curl ) return 0;
+
+	if( curlm )	// non blocking
+	{
+		resm = CURLM_CALL_MULTI_PERFORM;
+		while( resm == CURLM_CALL_MULTI_PERFORM )
+			resm = curl_multi_perform( curlm, &running );
+		if( resm == CURLM_OK )
+			state = ( running ? 1 : 0 );
+	}
+	else // blocking
+	{
+		// NOTE:
+		// blocking download has its own curl loop, so we need check events and update screen in Curl_ProgressCallback_f,
+		// this loop is not updating time cvars ( com_frameMsec, cls.realFrametime, cls.frametime, cls.realtime, ... )
+		// and this will cause client-server desynchronization, if download takes long time timeout can occur.
+		res = curl_easy_perform( curl ); // returns when error or download is completed/aborted
+		state = ( res == CURLE_OK ? 0 : -1 );
+	}
+
+	if( state != 1 ) // no continue ( done or error )
+		DL_End( res, resm );
+
+	return state;
+}
+
+
+
+void DL_Interrupt( void )
+{
+	if( !curl ) return;
+	Q_strncpyz( dl_error, "Download Interrupted.", sizeof(dl_error) );
+	DL_End( CURLE_OK, CURLM_OK );
+}
+
+
+
+void DL_Info( qboolean console )
+{
+	static double lastTime = 0.0;
+	double dltotal, dlnow, speed, time;
+	int timeleft;
+	CURLcode res;
+
+	if( !DL_Active() ) return;
+	if( cls.state != CA_CONNECTED && !console ) return;
+
+	res = curl_easy_getinfo( curl, CURLINFO_TOTAL_TIME, &time );					// total downloading time
+	if( res != CURLE_OK ) time = -1.0;
+
+	res = curl_easy_getinfo( curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dltotal );	// file size bytes
+	if( res != CURLE_OK || dltotal < 0.0 ) dltotal = 0.0;
+
+	res = curl_easy_getinfo( curl, CURLINFO_SIZE_DOWNLOAD, &dlnow );				// current bytes
+	if( res != CURLE_OK || dlnow < 0.0 ) dlnow = 0.0;
+	if( dltotal > 0.0 && dlnow > dltotal ) dlnow = 0.0;
+
+	res = curl_easy_getinfo( curl, CURLINFO_SPEED_DOWNLOAD, &speed );				// download rate bytes/sec
+	if( res != CURLE_OK ) speed = -1.0;
+
+	// update ui download progress screen cvars
+	if( cls.state == CA_CONNECTED )
+	{
+		Cvar_SetValue( "cl_downloadSize",  (float)dltotal );
+		Cvar_SetValue( "cl_downloadCount", (float)dlnow );
+	}
+
+	// print download progress in console
+	if( console && dl_showprogress->integer && dlnow > 0.0 )
+	{
+		// 8 times per second is enough
+		if( time-lastTime > 1.0/8.0 || time-lastTime < 0.0 || dlnow == dltotal )
+		{
+			lastTime = time;
+
+			if( dl_verbose->integer == 0 && dl_showprogress->integer == 2 && !curlm )
+				Com_Printf( "\r" ); // overwrite old progress line
+
+			if (dltotal != 0.0	// content-size is known
+					&& dlnow <= dltotal) {	// and appropriate
+				if (dltotal > 1024.0 * 1024.0) {	// MB range
+					Com_Printf("%.1f/%.1fMB", dlnow/1024.0/1024.0, dltotal/1024.0/1024.0);
+				} else if (dltotal > 10240.0) {		// KB range (>10KB)
+					Com_Printf("%.1f/%.1fKB", dlnow/1024.0, dltotal/1024.0);
+				} else {							// byte range
+					Com_Printf("%.0f/%.0fB", dlnow, dltotal);
+				}
+			} else {	// unknown content-size
+				if (dlnow > 1024.0 * 1024.0) {		// MB range
+					Com_Printf("%.1fMB", dlnow/1024.0/1024.0);
+				} else if (dlnow > 10240.0) {		// KB range (>10KB)
+					Com_Printf("%.1fKB", dlnow/1024.0);
+				} else {							// byte range
+					Com_Printf("%.0fB", dlnow);
+				}
+			}
+			if (speed >= 0.0) {
+				Com_Printf(" @%.1fKB/s", speed/1024.0);
+			}
+			if (dltotal != 0.0 && dlnow <= dltotal) {		
+				Com_Printf(" (%2.1f%%)", 100.0*dlnow/dltotal);
+				if( time > 0.0 && dlnow > 0.0 ) {
+					timeleft = (int) ( (dltotal-dlnow) * time/dlnow );
+					Com_Printf(" time left: %d:%0.2d", timeleft/60, timeleft%60);
+				}
+			}
+
+			if( dl_verbose->integer == 0 && dl_showprogress->integer == 2 && !curlm )
+				Com_Printf( "      " );	// make sure line is totally overwriten
+			else
+				Com_Printf( "\n" );		// or start a new line
+		}
+	}
+}
+
diff -wrubN quake3_1.32b/code/client/client.h dfengine_1.08_src/code/client/client.h
--- quake3_1.32b/code/client/client.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/client/client.h	2009-12-31 16:09:29.000000000 +0100
@@ -346,9 +346,13 @@
 extern	cvar_t	*cl_activeAction;
 
 extern	cvar_t	*cl_allowDownload;
+extern	cvar_t	*cl_mapAutoDownload;  // drakkar
+
 extern	cvar_t	*cl_conXOffset;
 extern	cvar_t	*cl_inGameVideo;
 
+extern	cvar_t	*in_keyboardShortcuts; // drakkar
+
 //=================================================
 
 //
@@ -449,6 +453,7 @@
 void Con_Bottom( void );
 void Con_Close( void );
 
+void Con_SetFrac( const float conFrac );	// marky
 
 //
 // cl_scrn.c
@@ -468,7 +473,7 @@
 
 void	SCR_DrawBigString( int x, int y, const char *s, float alpha );			// draws a string with embedded color control characters with fade
 void	SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color );	// ignores embedded color control characters
-void	SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor );
+void	SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean rawmode );
 void	SCR_DrawSmallChar( int x, int y, int ch );
 
 
@@ -517,3 +522,14 @@
 void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg);	//int length, const byte *data );
 void CL_Netchan_TransmitNextFragment( netchan_t *chan );
 qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg );
+
+//
+// cl_download.c
+//
+void DL_Init();
+void DL_Shutdown();
+int  DL_Active();
+int  DL_Begin( const char *map, qboolean nonblocking );
+int  DL_Continue( void );
+void DL_Interrupt( void );
+void DL_Info( qboolean console );
diff -wrubN quake3_1.32b/code/client/cl_keys.c dfengine_1.08_src/code/client/cl_keys.c
--- quake3_1.32b/code/client/cl_keys.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/client/cl_keys.c	2009-12-31 16:09:29.000000000 +0100
@@ -45,6 +45,8 @@
 qboolean	anykeydown;
 qkey_t		keys[MAX_KEYS];
 
+cvar_t 		*con_height; //marky
+
 
 typedef struct {
 	char	*name;
@@ -68,6 +70,10 @@
 	{"ALT", K_ALT},
 	{"CTRL", K_CTRL},
 	{"SHIFT", K_SHIFT},
+// drakkar
+	{"WIN", K_WIN},
+	{"MENU", K_MENU},
+// !drakkar
 
 	{"COMMAND", K_COMMAND},
 
@@ -245,7 +251,7 @@
 		float	color[4];
 
 		color[0] = color[1] = color[2] = color[3] = 1.0;
-		SCR_DrawSmallStringExt( x, y, str, color, qfalse );
+		SCR_DrawSmallStringExt( x, y, str, color, qfalse, qtrue );
 	} else {
 		// draw big string with drop shadow
 		SCR_DrawBigString( x, y, str, 1.0 );
@@ -266,7 +272,7 @@
 		cursorChar = 10;
 	}
 
-	i = drawLen - ( Q_PrintStrlen( str ) + 1 );
+	i = drawLen - ( strlen( str ) + 1 );	// Cgg - was Q_PrintStrlen()
 
 	if ( size == SMALLCHAR_WIDTH ) {
 		SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
@@ -510,10 +516,16 @@
 			}
 		}
 
+// drakkar - do not insert this lines in history buffer ( empty lines )
+if( Q_stricmp( g_consoleField.buffer, ""   )
+ && Q_stricmp( g_consoleField.buffer, "/"  )
+ && Q_stricmp( g_consoleField.buffer, "\\" ) )
+{ // !drakkar
 		// copy line to history buffer
 		historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;
 		nextHistoryLine++;
 		historyLine = nextHistoryLine;
+}
 
 		Field_Clear( &g_consoleField );
 
@@ -534,7 +546,7 @@
 
 	// command history (ctrl-p ctrl-n for unix style)
 
-	if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
+	if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || /*( key == K_KP_UPARROW ) ||*/   // drakkar - K_KP_UPARROW writes '8'
 		 ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {
 		if ( nextHistoryLine - historyLine < COMMAND_HISTORY 
 			&& historyLine > 0 ) {
@@ -544,7 +556,7 @@
 		return;
 	}
 
-	if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
+	if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || /*( key == K_KP_DOWNARROW ) ||*/   // drakkar - K_KP_DOWNARROW writes '2'
 		 ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {
 		if (historyLine == nextHistoryLine)
 			return;
@@ -1040,37 +1052,34 @@
 		}
 	}
 
-#ifdef __linux__
-  if (key == K_ENTER)
-  {
-    if (down)
-    {
-      if (keys[K_ALT].down)
+// drakkar - alt-enter swaps fullscreen
+#if ( __linux__ || _WIN32 )
+	if( keys[K_ALT].down && keys[K_ENTER].repeats == 1 )
       {
         Key_ClearStates();
-        if (Cvar_VariableValue("r_fullscreen") == 0)
-        {
-          Com_Printf("Switching to fullscreen rendering\n");
-          Cvar_Set("r_fullscreen", "1");
-        }
-        else
-        {
-          Com_Printf("Switching to windowed rendering\n");
-          Cvar_Set("r_fullscreen", "0");
-        }
-        Cbuf_ExecuteText( EXEC_APPEND, "vid_restart\n");
+		Cbuf_ExecuteText( EXEC_APPEND, "windowMode swapFullscreen\n" );
         return;
       }
-    }
-  }
 #endif
+// !drakkar
 
 	// console key is hardcoded, so the user can never unbind it
 	if (key == '`' || key == '~') {
 		if (!down) {
 			return;
 		}
+		//marky
+		con_height = Cvar_Get("con_height", "0.5", CVAR_ARCHIVE);	//called early, used as default (set by user)
+		Con_SetFrac(con_height->value);				
+		if(key == '`' || key == '~') {
+			if(keys[K_ALT].down)
+				Con_SetFrac(1.0f);
+			else if (keys[K_SHIFT].down)			// We use shift because CTRL doesn't want to work...
+				Con_SetFrac(.25f);
+			}
+		// !marky
     Con_ToggleConsole_f ();
+//		Key_ClearStates();	// marky
 		return;
 	}
 
@@ -1087,6 +1096,14 @@
 
 	// escape is always handled special
 	if ( key == K_ESCAPE && down ) {
+		// Cgg
+		if (DL_Active()) {
+			if( cls.state == CA_CONNECTED ) {	// drakkar - escape key aborts current download if we are connecting
+				DL_Interrupt();
+			}
+			return;
+		}
+		// !Cgg
 		if ( cls.keyCatchers & KEYCATCH_MESSAGE ) {
 			// clear message mode
 			Message_Key( key );
@@ -1204,8 +1221,9 @@
 ===================
 */
 void CL_CharEvent( int key ) {
-	// the console key should never be used as a char
-	if ( key == '`' || key == '~' ) {
+
+	// ignore chars when console is opening/closing
+	if( keys['~'].down || keys['`'].down ) {
 		return;
 	}
 
diff -wrubN quake3_1.32b/code/client/cl_main.c dfengine_1.08_src/code/client/cl_main.c
--- quake3_1.32b/code/client/cl_main.c	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/client/cl_main.c	2010-01-20 14:29:58.000000000 +0100
@@ -63,6 +63,8 @@
 cvar_t	*cl_motdString;
 
 cvar_t	*cl_allowDownload;
+cvar_t	*cl_mapAutoDownload; // drakkar
+
 cvar_t	*cl_conXOffset;
 cvar_t	*cl_inGameVideo;
 
@@ -500,12 +502,13 @@
 	char		retry[MAX_OSPATH];
 
 	if (Cmd_Argc() != 2) {
-		Com_Printf ("playdemo <demoname>\n");
+		Com_Printf ("usage: demo <demoname>\n");
 		return;
 	}
 
 	// make sure a local server is killed
 	Cvar_Set( "sv_killserver", "1" );
+	SV_Frame(0);	// Cgg - kill it now
 
 	CL_Disconnect( qtrue );
 
@@ -1389,6 +1392,7 @@
 	Cvar_Set( "cl_downloadSize", "0" );
 	Cvar_Set( "cl_downloadCount", "0" );
 	Cvar_SetValue( "cl_downloadTime", cls.realtime );
+	Cvar_Set( "cl_downloadMotd", "" );	// Cgg
 
 	clc.downloadBlock = 0; // Starting new file
 	clc.downloadCount = 0;
@@ -1480,6 +1484,25 @@
 
 	}
 		
+	// drakkar
+	if( cl_mapAutoDownload->integer )
+	{
+		const char *info, *mapname, *bsp;
+
+		// get map name and BSP file name
+		info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
+		mapname = Info_ValueForKey( info, "mapname" );
+		bsp = va( "maps/%s.bsp", mapname );
+
+		if( !FS_FileExists( bsp ) && FS_FileIsInPAK( bsp, NULL ) == -1 )
+		{
+			cls.state = CA_CONNECTED; // prevent continue loading and shows the ui download progress screen
+			DL_Begin( mapname, qtrue ); // nonblocking download continues in CL_Frame() : DL_Continue()
+			return;
+		}
+	}
+	// !drakkar
+
 	CL_DownloadsComplete();
 }
 
@@ -1973,7 +1996,7 @@
 */
 void CL_CheckUserinfo( void ) {
 	// don't add reliable commands when not yet connected
-	if ( cls.state < CA_CHALLENGING ) {
+	if ( cls.state < CA_CONNECTED && cls.state != CA_CINEMATIC ) {	// Cgg - was < CA_CHALLENGING 
 		return;
 	}
 	// don't overflow the reliable command buffer when paused
@@ -2036,6 +2059,12 @@
 		SCR_DebugGraph ( cls.realFrametime * 0.25, 0 );
 	}
 
+	// drakkar - if nonblocking download in progress try to download some bytes more
+	if( DL_Active() == 2 ) {
+		DL_Continue();
+	}
+	// !drakkar
+
 	// see if we need to update any userinfo
 	CL_CheckUserinfo();
 
@@ -2279,7 +2308,10 @@
 	// register our variables
 	//
 	cl_noprint = Cvar_Get( "cl_noprint", "0", 0 );
-	cl_motd = Cvar_Get ("cl_motd", "1", 0);
+	cl_motd = Cvar_Get ("cl_motd", "0", 0);	// Cgg - global q3 motd
+											// Id's server replies with icmp "port unreachable".
+											// Making it disabled by default - saves a dns query, 
+											// an udp packet + the resulting icmp message.
 
 	cl_timeout = Cvar_Get ("cl_timeout", "200", 0);
 
@@ -2312,6 +2344,7 @@
 	cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0);
 
 	cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE);
+	cl_mapAutoDownload = Cvar_Get ("cl_mapAutoDownload", "1", CVAR_ARCHIVE); // drakkar
 
 	cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0);
 #ifdef MACOS_X
@@ -2396,6 +2429,8 @@
 
 	SCR_Init ();
 
+	DL_Init();	// Cgg - client download
+
 	Cbuf_Execute ();
 
 	Cvar_Set( "cl_running", "1" );
@@ -2448,6 +2483,8 @@
 	Cmd_RemoveCommand ("showip");
 	Cmd_RemoveCommand ("model");
 
+	DL_Shutdown();	// Cgg
+	
 	Cvar_Set( "cl_running", "0" );
 
 	recursive = qfalse;
@@ -3320,5 +3357,3 @@
 
 	return qfalse;
 }
-
-
diff -wrubN quake3_1.32b/code/client/cl_parse.c dfengine_1.08_src/code/client/cl_parse.c
--- quake3_1.32b/code/client/cl_parse.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/client/cl_parse.c	2009-08-11 16:53:20.000000000 +0200
@@ -255,6 +255,16 @@
 
 	// read areamask
 	len = MSG_ReadByte( msg );
+	// Cgg - ioquake3 rev 796
+	// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+	// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+	// for the advisory.
+	if(len > sizeof(newSnap.areamask))
+	{
+		Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask.", len);
+		return;
+	}
+	// !Cgg
 	MSG_ReadData( msg, &newSnap.areamask, len);
 
 	// read playerinfo
@@ -370,6 +380,14 @@
 			gameSet = qtrue;
 		}
 
+		// Cgg - this shouldn't apply to loopback clients.
+		// They already have a proper set of values and in some cases
+		// the engine may end up in a race condition when fast cvar 
+		// transitions occur.
+		if (clc.serverAddress.type == NA_LOOPBACK) {
+			continue;
+		}
+		// !Cgg
 		Cvar_Set( key, value );
 	}
 	// if game folder should not be set and it is set at the client side
@@ -475,6 +493,17 @@
 	unsigned char data[MAX_MSGLEN];
 	int block;
 
+	// Cgg - ioquake3 rev 796
+	// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+	// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+	// for the advisory.
+	if (!*clc.downloadTempName) {
+		Com_Printf("Server sending download, but no download was requested\n");
+		CL_AddReliableCommand( "stopdl" );
+		return;
+	}
+	// !Cgg
+
 	// read the data
 	block = MSG_ReadShort ( msg );
 
@@ -493,8 +522,17 @@
 	}
 
 	size = MSG_ReadShort ( msg );
-	if (size > 0)
+	// Cgg - ioquake3 rev 796
+	// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+	// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+	// for the advisory.
+	if (size < 0 || size > sizeof(data))
+	{
+		Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size);
+		return;
+	}
 		MSG_ReadData( msg, data, size );
+	// !Cgg
 
 	if (clc.downloadBlock != block) {
 		Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
@@ -504,11 +542,17 @@
 	// open the file if not opened yet
 	if (!clc.download)
 	{
+		// Cgg - ioquake3 rev 796
+		// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+		// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+		// for the advisory.
+	/*
 		if (!*clc.downloadTempName) {
 			Com_Printf("Server sending download, but no download was requested\n");
 			CL_AddReliableCommand( "stopdl" );
 			return;
-		}
+		}*/
+		// !Cgg
 
 		clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
 
diff -wrubN quake3_1.32b/code/client/cl_scrn.c dfengine_1.08_src/code/client/cl_scrn.c
--- quake3_1.32b/code/client/cl_scrn.c	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/client/cl_scrn.c	2009-04-18 19:35:58.000000000 +0200
@@ -30,7 +30,7 @@
 cvar_t		*cl_graphheight;
 cvar_t		*cl_graphscale;
 cvar_t		*cl_graphshift;
-cvar_t		*cl_showRecording;	// Cgg
+cvar_t		*ch_recordMessage;	// Cgg
 
 /*
 ================
@@ -213,6 +213,11 @@
 			s += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
+			s++;
+		}
+		// !Cgg
 		SCR_DrawChar( xx+2, y+2, size, *s );
 		xx += size;
 		s++;
@@ -233,6 +238,11 @@
 			s += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
+			s++;
+		}
+		// !Cgg
 		SCR_DrawChar( xx, y, size, *s );
 		xx += size;
 		s++;
@@ -264,7 +274,8 @@
 Coordinates are at 640 by 480 virtual resolution
 ==================
 */
-void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor ) {
+// Cgg - added rawmode: stops color sequences from being interpreted
+void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean rawmode ) {
 	vec4_t		color;
 	const char	*s;
 	int			xx;
@@ -274,7 +285,7 @@
 	xx = x;
 	re.SetColor( setColor );
 	while ( *s ) {
-		if ( Q_IsColorString( s ) ) {
+		if ( !rawmode && Q_IsColorString( s ) ) {
 			if ( !forceColor ) {
 				Com_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
 				color[3] = setColor[3];
@@ -283,6 +294,11 @@
 			s += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) failed
+		if (!rawmode && *s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
+			s++;
+		}
+		// !Cgg
 		SCR_DrawSmallChar( xx, y, *s );
 		xx += SMALLCHAR_WIDTH;
 		s++;
@@ -302,10 +318,15 @@
 	while ( *s ) {
 		if ( Q_IsColorString( s ) ) {
 			s += 2;
-		} else {
-			count++;
+			continue;
+		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
 			s++;
 		}
+		// !Cgg
+		count++;
+		s++;
 	}
 
 	return count;
@@ -331,7 +352,7 @@
 	int		pos;
 
 	// Cgg - off by default
-	if (!cl_showRecording->integer) {
+	if (!ch_recordMessage->integer) {
 		return;
 	}
 	// !Cgg
@@ -428,7 +449,7 @@
 	cl_graphheight = Cvar_Get ("graphheight", "32", CVAR_CHEAT);
 	cl_graphscale = Cvar_Get ("graphscale", "1", CVAR_CHEAT);
 	cl_graphshift = Cvar_Get ("graphshift", "0", CVAR_CHEAT);
-	cl_showRecording = Cvar_Get ("cl_showRecording", "0", CVAR_ARCHIVE);	// Cgg
+	ch_recordMessage = Cvar_Get ("ch_recordMessage", "0", CVAR_ARCHIVE);	// Cgg
 
 	scr_initialized = qtrue;
 }
diff -wrubN quake3_1.32b/code/client/snd_dma.c dfengine_1.08_src/code/client/snd_dma.c
--- quake3_1.32b/code/client/snd_dma.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/client/snd_dma.c	2009-05-26 12:06:05.000000000 +0200
@@ -181,7 +181,9 @@
 
 		S_StopAllSounds ();
 
-		S_SoundInfo_f();
+		// Cgg - spammy
+		//S_SoundInfo_f();
+		// !Cgg
 	}
 
 }
diff -wrubN quake3_1.32b/code/game/q_math.c dfengine_1.08_src/code/game/q_math.c
--- quake3_1.32b/code/game/q_math.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/game/q_math.c	2009-04-18 19:35:58.000000000 +0200
@@ -36,11 +36,12 @@
 vec4_t		colorMagenta= {1, 0, 1, 1};
 vec4_t		colorCyan	= {0, 1, 1, 1};
 vec4_t		colorWhite	= {1, 1, 1, 1};
+vec4_t		colorOrange	= {1, 0.5, 0, 1};
 vec4_t		colorLtGrey	= {0.75, 0.75, 0.75, 1};
 vec4_t		colorMdGrey	= {0.5, 0.5, 0.5, 1};
 vec4_t		colorDkGrey	= {0.25, 0.25, 0.25, 1};
 
-vec4_t	g_color_table[8] =
+vec4_t	g_color_table[10] =
 	{
 	{0.0, 0.0, 0.0, 1.0},
 	{1.0, 0.0, 0.0, 1.0},
@@ -50,6 +51,8 @@
 	{0.0, 1.0, 1.0, 1.0},
 	{1.0, 0.0, 1.0, 1.0},
 	{1.0, 1.0, 1.0, 1.0},
+	{1.0, 0.5, 0.0, 1.0},
+	{0.5, 0.5, 0.5, 1.0}
 	};
 
 
diff -wrubN quake3_1.32b/code/game/q_shared.c dfengine_1.08_src/code/game/q_shared.c
--- quake3_1.32b/code/game/q_shared.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/game/q_shared.c	2009-04-18 19:35:58.000000000 +0200
@@ -837,6 +837,11 @@
 			p += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*p == Q_COLOR_ESCAPE && *(p+1) == Q_COLOR_ESCAPE) {
+			p++;
+		}
+		// !Cgg
 		p++;
 		len++;
 	}
@@ -848,20 +853,25 @@
 char *Q_CleanStr( char *string ) {
 	char*	d;
 	char*	s;
-	int		c;
 
 	s = string;
 	d = string;
-	while ((c = *s) != 0 ) {
+	// Cgg - repeated escape codes (^^) were broken
+	while (*s) {
 		if ( Q_IsColorString( s ) ) {
+			s += 2;
+			continue;
+		}
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
 			s++;
 		}		
-		else if ( c >= 0x20 && c <= 0x7E ) {
-			*d++ = c;
+		if (*s >= 0x20 && *s <= 0x7E) {
+			*d++ = *s;
 		}
 		s++;
 	}
 	*d = '\0';
+	// !Cgg
 
 	return string;
 }
diff -wrubN quake3_1.32b/code/game/q_shared.h dfengine_1.08_src/code/game/q_shared.h
--- quake3_1.32b/code/game/q_shared.h	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/game/q_shared.h	2010-01-20 13:23:26.000000000 +0100
@@ -26,8 +26,11 @@
 // q_shared.h -- included first by ALL program modules.
 // A user mod should never modify this file
 
-#define	Q3_VERSION		"Q3 1.32b"
+// Cgg
+#define	Q3_VERSION		"dfengine 1.08"
 // 1.32 released 7-10-2002
+#define Q3_WINDOW_TITLE Q3_VERSION
+// !Cgg
 
 #define MAX_TEAMNAME 32
 
@@ -54,7 +57,13 @@
 #pragma warning(disable : 4702)		// unreachable code
 #pragma warning(disable : 4711)		// selected for automatic inline expansion
 #pragma warning(disable : 4220)		// varargs matches remaining parameters
-#define _CRT_SECURE_NO_WARNINGS 1	// Cgg - disabling deprecated warnings in crt functions with msvc 2008
+// Cgg - disable various recent msvc warnings regarding "deprecated" C library functions.
+// Complying with this would impede the code portability either way.
+// Besides quake for the most part provides its own "secure" implementation of libc functions.
+#define _CRT_SECURE_NO_WARNINGS 1
+#define _CRT_SECURE_NO_DEPRECATE 1
+#pragma warning(disable : 4996)
+// !Cgg
 #endif
 
 /**********************************************************************
@@ -160,6 +169,9 @@
 
 #define	PATH_SEP '\\'
 
+// Cgg - portability
+#define strncasecmp strnicmp
+
 #endif
 
 //======================= MAC OS X DEFINES =====================
@@ -526,6 +538,7 @@
 extern	vec4_t		colorMagenta;
 extern	vec4_t		colorCyan;
 extern	vec4_t		colorWhite;
+extern	vec4_t		colorOrange;
 extern	vec4_t		colorLtGrey;
 extern	vec4_t		colorMdGrey;
 extern	vec4_t		colorDkGrey;
@@ -541,7 +554,9 @@
 #define COLOR_CYAN		'5'
 #define COLOR_MAGENTA	'6'
 #define COLOR_WHITE		'7'
-#define ColorIndex(c)	( ( (c) - '0' ) & 7 )
+#define COLOR_ORANGE	'8'
+#define COLOR_MDGREY	'9'
+#define ColorIndex(c)	( ( ( (c) - '0' ) &15 ) %10 )
 
 #define S_COLOR_BLACK	"^0"
 #define S_COLOR_RED		"^1"
@@ -551,8 +566,10 @@
 #define S_COLOR_CYAN	"^5"
 #define S_COLOR_MAGENTA	"^6"
 #define S_COLOR_WHITE	"^7"
+#define S_COLOR_ORANGE	"^8"
+#define S_COLOR_MDGREY	"^9"
 
-extern vec4_t	g_color_table[8];
+extern vec4_t	g_color_table[10];
 
 #define	MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b
 #define	MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a
diff -wrubN quake3_1.32b/code/qcommon/cmd.c dfengine_1.08_src/code/qcommon/cmd.c
--- quake3_1.32b/code/qcommon/cmd.c	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/qcommon/cmd.c	2009-04-18 19:34:04.000000000 +0200
@@ -24,7 +24,10 @@
 #include "../game/q_shared.h"
 #include "qcommon.h"
 
-#define	MAX_CMD_BUFFER	16384
+// Cgg - expanding command buffer from 16k to 64k
+//#define	MAX_CMD_BUFFER	16384
+#define	MAX_CMD_BUFFER	0x10000
+// !Cgg
 #define	MAX_CMD_LINE	1024
 
 typedef struct {
@@ -240,7 +243,6 @@
 	char	*f;
 	int		len;
 	char	filename[MAX_QPATH];
-	char	*c, *lf, *s;	// Cgg
 
 	if (Cmd_Argc () != 2) {
 		Com_Printf ("exec <filename> : execute a script file\n");
@@ -256,23 +258,7 @@
 	}
 	Com_Printf ("execing %s\n",Cmd_Argv(1));
 
-	// Cgg - execute the file buffer incrementally
-	Cbuf_Execute();
-	for (c=f,s=f,lf=f; *c; c++) {
-		if (*c == '\n') {
-			lf = c;
-		}
-		if (c - s >= 0x4000 -1) {
-			*lf = 0;
-			Cbuf_InsertText(s);
-			Cbuf_Execute();
-			s = lf+1;
-		}
-	}
-	Cbuf_InsertText(s);
-	Cbuf_Execute();
-	//was: Cbuf_InsertText (f);
-	// !Cgg
+	Cbuf_InsertText (f);
 
 	FS_FreeFile (f);
 }
diff -wrubN quake3_1.32b/code/qcommon/common.c dfengine_1.08_src/code/qcommon/common.c
--- quake3_1.32b/code/qcommon/common.c	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/qcommon/common.c	2009-12-09 16:44:14.000000000 +0100
@@ -45,8 +45,8 @@
 #define DEF_COMHUNKMEGS "64"
 #define DEF_COMZONEMEGS "24"
 #else
-#define DEF_COMHUNKMEGS "56"
-#define DEF_COMZONEMEGS "16"
+#define DEF_COMHUNKMEGS "64"	// Cgg: was 56
+#define DEF_COMZONEMEGS "24"	// Cgg: was 16
 #endif
 
 int		com_argc;
@@ -69,6 +69,7 @@
 cvar_t	*com_dropsim;		// 0.0 to 1.0, simulated packet drops
 cvar_t	*com_journal;
 cvar_t	*com_maxfps;
+cvar_t	*com_sleepfps;		// Cgg: fps limit applied when the game loses focus
 cvar_t	*com_timedemo;
 cvar_t	*com_sv_running;
 cvar_t	*com_cl_running;
@@ -237,7 +238,7 @@
 
 #if defined(_WIN32) && defined(_DEBUG)
 	if ( code != ERR_DISCONNECT && code != ERR_NEED_CD ) {
-		if (!com_noErrorInterrupt->integer) {
+		if ( !com_noErrorInterrupt || !com_noErrorInterrupt->integer ) {  // drakkar - check null pointer
 			__asm {
 				int 0x03
 			}
@@ -1387,7 +1388,8 @@
 void Com_InitZoneMemory( void ) {
 	cvar_t	*cv;
 	// allocate the random block zone
-	cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS, CVAR_LATCH | CVAR_ARCHIVE );
+	Com_StartupVariable("com_zoneMegs");	// Cgg: config files and command line options haven't been taken in account yet
+	cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS, CVAR_LATCH );	// Cgg: was CVAR_ARCHIVE. Does not have meaning as this cvar can only be set through the command line
 
 	if ( cv->integer < 20 ) {
 		s_zoneTotal = 1024 * 1024 * 16;
@@ -2417,6 +2419,7 @@
 	// init commands and vars
 	//
 	com_maxfps = Cvar_Get ("com_maxfps", "85", CVAR_ARCHIVE);
+	com_sleepfps = Cvar_Get ("com_sleepfps", "10", CVAR_ARCHIVE);	// Cgg
 	com_blood = Cvar_Get ("com_blood", "1", CVAR_ARCHIVE);
 
 	com_developer = Cvar_Get ("developer", "0", CVAR_TEMP );
@@ -3209,11 +3212,14 @@
 	}
 
 	// cut shortestMatch to the amount common with s
-	for ( i = 0 ; s[i] ; i++ ) {
+	// Cgg - was wrong when s had fewer chars than shortestMatch
+	i = 0;
+	do {
 		if ( tolower(shortestMatch[i]) != tolower(s[i]) ) {
 			shortestMatch[i] = 0;
 		}
-	}
+	} while (s[i++]);
+	// !Cgg
 }
 
 /*
@@ -3314,6 +3320,9 @@
 		}
 		Maps_CommandCompletion(FindMatches);
 		Com_sprintf(completionField->buffer, sizeof(completionField->buffer), "\\%s %s", cmd, (shortestMatch[0]) ? shortestMatch : Cmd_Argv(1));
+		if (matchCount == 1) { // drakkar - space on match, like in linux console
+			Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
+		}
 		completionField->cursor = strlen(completionField->buffer);
 		if (matchCount < 2) {
 			return;
@@ -3334,6 +3343,9 @@
 		}
 		Demos_CommandCompletion(FindMatches);
 		Com_sprintf(completionField->buffer, sizeof(completionField->buffer), "\\%s %s", cmd, (shortestMatch[0]) ? shortestMatch : Cmd_Argv(1));
+		if (matchCount == 1) { // drakkar - space on match, like in linux console
+			Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
+		}
 		completionField->cursor = strlen(completionField->buffer);
 		if (matchCount < 2) {
 			return;
diff -wrubN quake3_1.32b/code/qcommon/files.c dfengine_1.08_src/code/qcommon/files.c
--- quake3_1.32b/code/qcommon/files.c	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/qcommon/files.c	2009-04-18 19:37:40.000000000 +0200
@@ -565,8 +565,9 @@
 
 ===========
 */
-static void FS_Remove( const char *osPath ) {
-	remove( osPath );
+// Cgg - returns qboolean
+static qboolean FS_Remove( const char *osPath ) {
+	return !remove( osPath );
 }
 
 /*
@@ -2511,8 +2512,40 @@
 	}
 	FS_FreeFileList(matches);
 
-	// demos
-	matches = FS_ListFilteredFiles(searchpath, ".dm_6?", NULL, &n);
+	// .dm_68
+	matches = FS_ListFilteredFiles(searchpath, ".dm_68", NULL, &n);
+	for (i=0; i<n; i++) {
+		// filter hidden files out
+		if (matches[i][0] == '.') {
+			continue;
+		}
+		if (strlen(path)) {
+			Com_sprintf(m, sizeof(m), "%s/%s", path, matches[i]);
+			nlist = FS_AddFileToList(m, list, nlist);
+			continue;
+		}
+		nlist = FS_AddFileToList(matches[i], list, nlist);
+	}
+	FS_FreeFileList(matches);
+
+	// .dm_67
+	matches = FS_ListFilteredFiles(searchpath, ".dm_67", NULL, &n);
+	for (i=0; i<n; i++) {
+		// filter hidden files out
+		if (matches[i][0] == '.') {
+			continue;
+		}
+		if (strlen(path)) {
+			Com_sprintf(m, sizeof(m), "%s/%s", path, matches[i]);
+			nlist = FS_AddFileToList(m, list, nlist);
+			continue;
+		}
+		nlist = FS_AddFileToList(matches[i], list, nlist);
+	}
+	FS_FreeFileList(matches);
+
+	// .dm_66
+	matches = FS_ListFilteredFiles(searchpath, ".dm_66", NULL, &n);
 	for (i=0; i<n; i++) {
 		// filter hidden files out
 		if (matches[i][0] == '.') {
@@ -2627,7 +2660,8 @@
 FS_idPak
 ================
 */
-qboolean FS_idPak( char *pak, char *base ) {
+// Cgg - added const qualifier
+qboolean FS_idPak( const char *pak, const char *base ) {
 	int i;
 
 	for (i = 0; i < NUM_ID_PAKS; i++) {
@@ -2853,7 +2887,7 @@
 		homePath = fs_basepath->string;
 	}
 	fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT );
-	fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
+	fs_gamedirvar = Cvar_Get ("fs_game", "defrag", CVAR_INIT|CVAR_SYSTEMINFO );
 	fs_restrict = Cvar_Get ("fs_restrict", "", CVAR_INIT );
 
 	// add search path elements in reverse priority order
@@ -2911,8 +2945,10 @@
 	// reorder the pure pk3 files according to server order
 	FS_ReorderPurePaks();
 	
+// Cgg - gets spammy pretty quickly
 	// print the current search paths
-	FS_Path_f();
+//	FS_Path_f();
+// !Cgg
 
 	fs_gamedirvar->modified = qfalse; // We just loaded, it's not modified
 
@@ -3517,3 +3553,54 @@
 	fflush(fsh[f].handleFiles.file.o);
 }
 
+// Cgg
+// return the current gamedir (eg. "baseq3", "mymod", ...)
+const char *FS_GetGameDir() {
+	return fs_gamedir;
+}
+
+// remove a file from the homepath (eg. C:\quake3\; ~/.q3a/).
+qboolean FS_SV_RemoveFile(const char *qpath) {
+	char stripped[MAX_OSPATH];
+	char *ospath;
+	const char *c;
+	char *ext;
+
+	// make sure the given path doesn't try to climb up the file hierarchy.
+	if (strstr(qpath, "..") || strstr(qpath, "::")) {
+		Com_Printf("Warning: attempted to remove file with invalid path.\n");
+		return qfalse;
+	}
+	// prevent files in base directory from being removed - only files in subdirs can be.
+	for (c=qpath; *c == '/' || *c == '\\'; c++)
+		;
+	if (!strchr(c, '/') && !strchr(c, '\\')) {
+		Com_Printf("Warning: attempted to remove file from base directory.\n");
+		return qfalse;
+	}
+	// prevent id's packs from being removed.
+	// FS_idPak() takes a path without the pk3 extension.
+	Q_strncpyz(stripped, qpath, sizeof(stripped));
+	ext = stripped + strlen(stripped) -4;
+	if (ext > stripped && !strcmp(ext, ".pk3")) {
+		*ext = 0;
+		if (FS_idPak(stripped, "baseq3") || FS_idPak(stripped, "missionpack")) {
+			Com_Printf("Warning: attempted to remove Id's game packs.\n");
+			return qfalse;
+		}
+	}
+	// remove
+	ospath = FS_BuildOSPath(fs_homepath->string, qpath, "");
+	ospath[strlen(ospath)-1] = 0;
+	if (!FS_Remove(ospath)) {
+		Com_Printf("Warning: failed to remove file: %s\n", ospath);
+		return qfalse;
+	}
+	return qtrue;
+}
+
+// remove a file from homepath/gamedir (eg. C:\quake3\mymod\; ~/.q3a/mymod)
+qboolean FS_RemoveFile(const char *filename) {
+	return FS_SV_RemoveFile(va("%s/%s", fs_gamedir, filename));
+}
+// !Cgg
diff -wrubN quake3_1.32b/code/qcommon/huffman.c dfengine_1.08_src/code/qcommon/huffman.c
--- quake3_1.32b/code/qcommon/huffman.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/qcommon/huffman.c	2009-05-18 13:44:57.000000000 +0200
@@ -268,25 +268,6 @@
 	return (*ch = node->symbol);
 }
 
-/* Get a symbol */
-void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) {
-	bloc = *offset;
-	while (node && node->symbol == INTERNAL_NODE) {
-		if (get_bit(fin)) {
-			node = node->right;
-		} else {
-			node = node->left;
-		}
-	}
-	if (!node) {
-		*ch = 0;
-		return;
-//		Com_Error(ERR_DROP, "Illegal tree!\n");
-	}
-	*ch = node->symbol;
-	*offset = bloc;
-}
-
 /* Send the prefix code for this node */
 static void send(node_t *node, node_t *child, byte *fout) {
 	if (node->parent) {
@@ -315,12 +296,6 @@
 	}
 }
 
-void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) {
-	bloc = *offset;
-	send(huff->loc[ch], NULL, fout);
-	*offset = bloc;
-}
-
 void Huff_Decompress(msg_t *mbuf, int offset) {
 	int			ch, cch, i, j, size;
 	byte		seq[65536];
@@ -413,25 +388,3 @@
 	mbuf->cursize = (bloc>>3) + offset;
 	Com_Memcpy(mbuf->data+offset, seq, (bloc>>3));
 }
-
-void Huff_Init(huffman_t *huff) {
-
-	Com_Memset(&huff->compressor, 0, sizeof(huff_t));
-	Com_Memset(&huff->decompressor, 0, sizeof(huff_t));
-
-	// Initialize the tree & list with the NYT node 
-	huff->decompressor.tree = huff->decompressor.lhead = huff->decompressor.ltail = huff->decompressor.loc[NYT] = &(huff->decompressor.nodeList[huff->decompressor.blocNode++]);
-	huff->decompressor.tree->symbol = NYT;
-	huff->decompressor.tree->weight = 0;
-	huff->decompressor.lhead->next = huff->decompressor.lhead->prev = NULL;
-	huff->decompressor.tree->parent = huff->decompressor.tree->left = huff->decompressor.tree->right = NULL;
-
-	// Add the NYT (not yet transmitted) node into the tree/list */
-	huff->compressor.tree = huff->compressor.lhead = huff->compressor.loc[NYT] =  &(huff->compressor.nodeList[huff->compressor.blocNode++]);
-	huff->compressor.tree->symbol = NYT;
-	huff->compressor.tree->weight = 0;
-	huff->compressor.lhead->next = huff->compressor.lhead->prev = NULL;
-	huff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL;
-	huff->compressor.loc[NYT] = huff->compressor.tree;
-}
-
diff -wrubN quake3_1.32b/code/qcommon/huffman_static.c dfengine_1.08_src/code/qcommon/huffman_static.c
--- quake3_1.32b/code/qcommon/huffman_static.c	1970-01-01 01:00:00.000000000 +0100
+++ dfengine_1.08_src/code/qcommon/huffman_static.c	2009-05-18 14:31:25.000000000 +0200
@@ -0,0 +1,347 @@
+/*
+===========================================================================
+Copyright (C) 2009 Cyril Gantin
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+
+Quake 3 uses a prerendered huffman tree to compress netchan messages.
+
+This version is more efficient - eats up less memory, initializes faster - because it uses
+a static code instead of feeding the adaptative huffman algorithm with predefined values.
+
+*/
+
+#include "../game/q_shared.h"
+#include "qcommon.h"
+
+typedef struct {
+	int code:16;
+	int nbits:16;
+} huff_code_t;
+
+static huff_code_t huff_q3code[] = {
+	{ 0x002, 2 },		// 0
+	{ 0x01b, 5 },		// 1
+	{ 0x048, 7 },		// 2
+	{ 0x06c, 7 },		// 3
+	{ 0x0a1, 8 },		// 4
+	{ 0x011, 8 },		// 5
+	{ 0x010, 7 },		// 6
+	{ 0x03f, 6 },		// 7
+	{ 0x015, 5 },		// 8
+	{ 0x034, 7 },		// 9
+	{ 0x069, 7 },		// 10
+	{ 0x00b, 7 },		// 11
+	{ 0x013, 7 },		// 12
+	{ 0x02d, 6 },		// 13
+	{ 0x039, 8 },		// 14
+	{ 0x0ac, 9 },		// 15
+	{ 0x025, 7 },		// 16
+	{ 0x058, 9 },		// 17
+	{ 0x1f0, 9 },		// 18
+	{ 0x1f8, 9 },		// 19
+	{ 0x1dd, 10 },		// 20
+	{ 0x3f3, 10 },		// 21
+	{ 0x22b, 10 },		// 22
+	{ 0x323, 10 },		// 23
+	{ 0x0f4, 9 },		// 24
+	{ 0x18d, 10 },		// 25
+	{ 0x0ab, 10 },		// 26
+	{ 0x363, 10 },		// 27
+	{ 0x1eb, 10 },		// 28
+	{ 0x043, 8 },		// 29
+	{ 0x04f, 9 },		// 30
+	{ 0x0d4, 8 },		// 31
+	{ 0x037, 6 },		// 32
+	{ 0x0d3, 10 },		// 33
+	{ 0x044, 9 },		// 34
+	{ 0x2cd, 10 },		// 35
+	{ 0x3c5, 10 },		// 36
+	{ 0x3f9, 10 },		// 37
+	{ 0x30d, 10 },		// 38
+	{ 0x3cd, 10 },		// 39
+	{ 0x094, 9 },		// 40
+	{ 0x1ac, 10 },		// 41
+	{ 0x033, 10 },		// 42
+	{ 0x014, 10 },		// 43
+	{ 0x271, 10 },		// 44
+	{ 0x2f0, 10 },		// 45
+	{ 0x1f4, 9 },		// 46
+	{ 0x078, 8 },		// 47
+	{ 0x027, 7 },		// 48
+	{ 0x0c3, 8 },		// 49
+	{ 0x0ef, 8 },		// 50
+	{ 0x197, 9 },		// 51
+	{ 0x053, 8 },		// 52
+	{ 0x0b1, 8 },		// 53
+	{ 0x00d, 9 },		// 54
+	{ 0x161, 9 },		// 55
+	{ 0x007, 9 },		// 56
+	{ 0x0f1, 9 },		// 57
+	{ 0x199, 9 },		// 58
+	{ 0x191, 10 },		// 59
+	{ 0x123, 10 },		// 60
+	{ 0x0bc, 9 },		// 61
+	{ 0x144, 9 },		// 62
+	{ 0x1f3, 10 },		// 63
+	{ 0x0cf, 8 },		// 64
+	{ 0x050, 7 },		// 65
+	{ 0x07c, 7 },		// 66
+	{ 0x004, 7 },		// 67
+	{ 0x021, 8 },		// 68
+	{ 0x051, 8 },		// 69
+	{ 0x080, 9 },		// 70
+	{ 0x070, 9 },		// 71
+	{ 0x13d, 9 },		// 72
+	{ 0x063, 10 },		// 73
+	{ 0x2d7, 10 },		// 74
+	{ 0x371, 10 },		// 75
+	{ 0x19d, 9 },		// 76
+	{ 0x2ab, 10 },		// 77
+	{ 0x1c7, 10 },		// 78
+	{ 0x333, 10 },		// 79
+	{ 0x12c, 9 },		// 80
+	{ 0x09d, 10 },		// 81
+	{ 0x16b, 10 },		// 82
+	{ 0x36b, 10 },		// 83
+	{ 0x1d3, 10 },		// 84
+	{ 0x171, 10 },		// 85
+	{ 0x1e3, 10 },		// 86
+	{ 0x233, 10 },		// 87
+	{ 0x0d7, 10 },		// 88
+	{ 0x2cb, 10 },		// 89
+	{ 0x170, 9 },		// 90
+	{ 0x0a8, 9 },		// 91
+	{ 0x0c7, 9 },		// 92
+	{ 0x105, 9 },		// 93
+	{ 0x0eb, 9 },		// 94
+	{ 0x0d8, 8 },		// 95
+	{ 0x0f3, 9 },		// 96
+	{ 0x03c, 8 },		// 97
+	{ 0x1ab, 9 },		// 98
+	{ 0x18f, 9 },		// 99
+	{ 0x097, 9 },		// 100
+	{ 0x030, 7 },		// 101
+	{ 0x041, 8 },		// 102
+	{ 0x14f, 9 },		// 103
+	{ 0x01c, 6 },		// 104
+	{ 0x028, 8 },		// 105
+	{ 0x0bd, 9 },		// 106
+	{ 0x0c4, 9 },		// 107
+	{ 0x098, 8 },		// 108
+	{ 0x08f, 9 },		// 109
+	{ 0x00c, 8 },		// 110
+	{ 0x0b3, 8 },		// 111
+	{ 0x085, 8 },		// 112
+	{ 0x08c, 8 },		// 113
+	{ 0x047, 8 },		// 114
+	{ 0x079, 8 },		// 115
+	{ 0x059, 7 },		// 116
+	{ 0x040, 7 },		// 117
+	{ 0x017, 8 },		// 118
+	{ 0x019, 8 },		// 119
+	{ 0x04b, 8 },		// 120
+	{ 0x0e1, 8 },		// 121
+	{ 0x0a3, 8 },		// 122
+	{ 0x073, 8 },		// 123
+	{ 0x06f, 8 },		// 124
+	{ 0x068, 7 },		// 125
+	{ 0x008, 7 },		// 126
+	{ 0x065, 7 },		// 127
+	{ 0x01f, 6 },		// 128
+	{ 0x029, 7 },		// 129
+	{ 0x04c, 7 },		// 130
+	{ 0x07d, 7 },		// 131
+	{ 0x00f, 8 },		// 132
+	{ 0x083, 8 },		// 133
+	{ 0x001, 8 },		// 134
+	{ 0x087, 8 },		// 135
+	{ 0x067, 8 },		// 136
+	{ 0x0e7, 8 },		// 137
+	{ 0x057, 8 },		// 138
+	{ 0x074, 8 },		// 139
+	{ 0x1cb, 9 },		// 140
+	{ 0x1c4, 9 },		// 141
+	{ 0x081, 9 },		// 142
+	{ 0x04d, 9 },		// 143
+	{ 0x131, 9 },		// 144
+	{ 0x163, 10 },		// 145
+	{ 0x180, 9 },		// 146
+	{ 0x3d7, 10 },		// 147
+	{ 0x02b, 10 },		// 148
+	{ 0x145, 10 },		// 149
+	{ 0x06b, 10 },		// 150
+	{ 0x03d, 10 },		// 151
+	{ 0x32b, 10 },		// 152
+	{ 0x0f9, 10 },		// 153
+	{ 0x0e3, 10 },		// 154
+	{ 0x245, 10 },		// 155
+	{ 0x12b, 10 },		// 156
+	{ 0x031, 10 },		// 157
+	{ 0x3eb, 10 },		// 158
+	{ 0x1b9, 10 },		// 159
+	{ 0x114, 9 },		// 160
+	{ 0x1f9, 10 },		// 161
+	{ 0x133, 10 },		// 162
+	{ 0x02c, 10 },		// 163
+	{ 0x2dd, 10 },		// 164
+	{ 0x1c1, 10 },		// 165
+	{ 0x31d, 10 },		// 166
+	{ 0x1d1, 10 },		// 167
+	{ 0x138, 9 },		// 168
+	{ 0x061, 10 },		// 169
+	{ 0x2e3, 10 },		// 170
+	{ 0x345, 10 },		// 171
+	{ 0x26b, 10 },		// 172
+	{ 0x0cd, 10 },		// 173
+	{ 0x0cb, 10 },		// 174
+	{ 0x14d, 10 },		// 175
+	{ 0x038, 9 },		// 176
+	{ 0x3c1, 10 },		// 177
+	{ 0x23d, 10 },		// 178
+	{ 0x3bc, 10 },		// 179
+	{ 0x0c5, 10 },		// 180
+	{ 0x3ac, 10 },		// 181
+	{ 0x3e3, 10 },		// 182
+	{ 0x299, 10 },		// 183
+	{ 0x3d3, 10 },		// 184
+	{ 0x214, 10 },		// 185
+	{ 0x203, 10 },		// 186
+	{ 0x1bc, 10 },		// 187
+	{ 0x29d, 10 },		// 188
+	{ 0x381, 10 },		// 189
+	{ 0x263, 10 },		// 190
+	{ 0x08d, 10 },		// 191
+	{ 0x054, 8 },		// 192
+	{ 0x103, 9 },		// 193
+	{ 0x05d, 8 },		// 194
+	{ 0x020, 6 },		// 195
+	{ 0x009, 7 },		// 196
+	{ 0x3c7, 10 },		// 197
+	{ 0x307, 10 },		// 198
+	{ 0x0b8, 8 },		// 199
+	{ 0x1f1, 9 },		// 200
+	{ 0x22c, 10 },		// 201
+	{ 0x045, 10 },		// 202
+	{ 0x003, 10 },		// 203
+	{ 0x11d, 10 },		// 204
+	{ 0x1c5, 10 },		// 205
+	{ 0x34d, 10 },		// 206
+	{ 0x01d, 10 },		// 207
+	{ 0x000, 9 },		// 208
+	{ 0x3b9, 10 },		// 209
+	{ 0x0dd, 10 },		// 210
+	{ 0x181, 10 },		// 211
+	{ 0x10d, 10 },		// 212
+	{ 0x0b9, 10 },		// 213
+	{ 0x1cd, 10 },		// 214
+	{ 0x394, 10 },		// 215
+	{ 0x1bd, 10 },		// 216
+	{ 0x194, 10 },		// 217
+	{ 0x38d, 10 },		// 218
+	{ 0x158, 10 },		// 219
+	{ 0x3bd, 10 },		// 220
+	{ 0x0c1, 10 },		// 221
+	{ 0x3dd, 10 },		// 222
+	{ 0x0f8, 10 },		// 223
+	{ 0x0d1, 9 },		// 224
+	{ 0x091, 9 },		// 225
+	{ 0x099, 10 },		// 226
+	{ 0x2f8, 10 },		// 227
+	{ 0x023, 10 },		// 228
+	{ 0x071, 10 },		// 229
+	{ 0x2d3, 10 },		// 230
+	{ 0x391, 10 },		// 231
+	{ 0x049, 7 },		// 232
+	{ 0x231, 10 },		// 233
+	{ 0x107, 10 },		// 234
+	{ 0x261, 10 },		// 235
+	{ 0x223, 10 },		// 236
+	{ 0x018, 8 },		// 237
+	{ 0x205, 10 },		// 238
+	{ 0x2c1, 10 },		// 239
+	{ 0x1d7, 10 },		// 240
+	{ 0x0f0, 10 },		// 241
+	{ 0x2c5, 10 },		// 242
+	{ 0x300, 10 },		// 243
+	{ 0x3d1, 10 },		// 244
+	{ 0x3a8, 10 },		// 245
+	{ 0x21d, 10 },		// 246
+	{ 0x500, 11 },		// 247
+	{ 0x005, 10 },		// 248
+	{ 0x358, 10 },		// 249
+	{ 0x2f9, 10 },		// 250
+	{ 0x1a8, 10 },		// 251
+	{ 0x2b9, 10 },		// 252
+	{ 0x28d, 10 },		// 253
+	{ 0x02f, 7 },		// 254
+	{ 0x024, 6 }		// 255
+};
+
+// adapted from huffman.c
+static void add_bit(char bit, byte *fout, int *offset) {
+	if ((*offset&7) == 0) {
+		fout[(*offset>>3)] = 0;
+	}
+	fout[(*offset>>3)] |= bit << (*offset&7);
+	(*offset)++;
+}
+
+// adapted from huffman.c
+static int get_bit(byte *fin, int *offset) {
+	int t;
+	t = (fin[(*offset>>3)] >> (*offset&7)) & 0x1;
+	(*offset)++;
+	return t;
+}
+
+static int getSymbolForCode(huff_code_t c) {
+	int i;
+	for (i=0; i<256; i++) {
+		if (huff_q3code[i].nbits == c.nbits && huff_q3code[i].code == c.code) {
+			return i;
+		}
+	}
+	return -1;
+}
+void Huff_offsetReceive(int *ch, byte *fin, int *offset) {
+	huff_code_t c;
+	memset(&c, 0, sizeof(c));
+	c.code |= get_bit(fin, offset) << c.nbits++;
+	c.code |= get_bit(fin, offset) << c.nbits++;
+	while ((*ch = getSymbolForCode(c)) == -1) {
+		c.code |= get_bit(fin, offset) << c.nbits++;
+		if (c.nbits	> 11) {
+			*ch = 0;
+			return;	/* code depth reached */
+		}
+	}
+}
+
+void Huff_offsetTransmit(int ch, byte *fout, int *offset) {
+	const huff_code_t *c;
+	int i;
+
+	if (ch < 0 || ch > 255) {
+		Com_Error(ERR_FATAL, "Huffman compression: invalid symbol 0x%x.", ch);
+	}
+	c = huff_q3code+ch;
+	for (i= 0; i<c->nbits; i++) {
+		add_bit((c->code>>i) &1, fout, offset);
+	}
+}
diff -wrubN quake3_1.32b/code/qcommon/msg.c dfengine_1.08_src/code/qcommon/msg.c
--- quake3_1.32b/code/qcommon/msg.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/qcommon/msg.c	2009-05-18 13:44:57.000000000 +0200
@@ -22,10 +22,6 @@
 #include "../game/q_shared.h"
 #include "qcommon.h"
 
-static huffman_t		msgHuff;
-
-static qboolean			msgInit = qfalse;
-
 int pcount[256];
 
 /*
@@ -39,21 +35,13 @@
 
 int oldsize = 0;
 
-void MSG_initHuffman();
-
 void MSG_Init( msg_t *buf, byte *data, int length ) {
-	if (!msgInit) {
-		MSG_initHuffman();
-	}
 	Com_Memset (buf, 0, sizeof(*buf));
 	buf->data = data;
 	buf->maxsize = length;
 }
 
 void MSG_InitOOB( msg_t *buf, byte *data, int length ) {
-	if (!msgInit) {
-		MSG_initHuffman();
-	}
 	Com_Memset (buf, 0, sizeof(*buf));
 	buf->data = data;
 	buf->maxsize = length;
@@ -172,7 +160,7 @@
 		if (bits) {
 			for(i=0;i<bits;i+=8) {
 //				fwrite(bp, 1, 1, fp);
-				Huff_offsetTransmit (&msgHuff.compressor, (value&0xff), msg->data, &msg->bit);
+				Huff_offsetTransmit ((value&0xff), msg->data, &msg->bit);
 				value = (value>>8);
 			}
 		}
@@ -227,7 +215,7 @@
 		if (bits) {
 //			fp = fopen("c:\\netchan.bin", "a");
 			for(i=0;i<bits;i+=8) {
-				Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit);
+				Huff_offsetReceive (&get, msg->data, &msg->bit);
 //				fwrite(&get, 1, 1, fp);
 				value |= (get<<(i+nbits));
 			}
@@ -1447,311 +1435,4 @@
 	}
 }
 
-int msg_hData[256] = {
-250315,			// 0
-41193,			// 1
-6292,			// 2
-7106,			// 3
-3730,			// 4
-3750,			// 5
-6110,			// 6
-23283,			// 7
-33317,			// 8
-6950,			// 9
-7838,			// 10
-9714,			// 11
-9257,			// 12
-17259,			// 13
-3949,			// 14
-1778,			// 15
-8288,			// 16
-1604,			// 17
-1590,			// 18
-1663,			// 19
-1100,			// 20
-1213,			// 21
-1238,			// 22
-1134,			// 23
-1749,			// 24
-1059,			// 25
-1246,			// 26
-1149,			// 27
-1273,			// 28
-4486,			// 29
-2805,			// 30
-3472,			// 31
-21819,			// 32
-1159,			// 33
-1670,			// 34
-1066,			// 35
-1043,			// 36
-1012,			// 37
-1053,			// 38
-1070,			// 39
-1726,			// 40
-888,			// 41
-1180,			// 42
-850,			// 43
-960,			// 44
-780,			// 45
-1752,			// 46
-3296,			// 47
-10630,			// 48
-4514,			// 49
-5881,			// 50
-2685,			// 51
-4650,			// 52
-3837,			// 53
-2093,			// 54
-1867,			// 55
-2584,			// 56
-1949,			// 57
-1972,			// 58
-940,			// 59
-1134,			// 60
-1788,			// 61
-1670,			// 62
-1206,			// 63
-5719,			// 64
-6128,			// 65
-7222,			// 66
-6654,			// 67
-3710,			// 68
-3795,			// 69
-1492,			// 70
-1524,			// 71
-2215,			// 72
-1140,			// 73
-1355,			// 74
-971,			// 75
-2180,			// 76
-1248,			// 77
-1328,			// 78
-1195,			// 79
-1770,			// 80
-1078,			// 81
-1264,			// 82
-1266,			// 83
-1168,			// 84
-965,			// 85
-1155,			// 86
-1186,			// 87
-1347,			// 88
-1228,			// 89
-1529,			// 90
-1600,			// 91
-2617,			// 92
-2048,			// 93
-2546,			// 94
-3275,			// 95
-2410,			// 96
-3585,			// 97
-2504,			// 98
-2800,			// 99
-2675,			// 100
-6146,			// 101
-3663,			// 102
-2840,			// 103
-14253,			// 104
-3164,			// 105
-2221,			// 106
-1687,			// 107
-3208,			// 108
-2739,			// 109
-3512,			// 110
-4796,			// 111
-4091,			// 112
-3515,			// 113
-5288,			// 114
-4016,			// 115
-7937,			// 116
-6031,			// 117
-5360,			// 118
-3924,			// 119
-4892,			// 120
-3743,			// 121
-4566,			// 122
-4807,			// 123
-5852,			// 124
-6400,			// 125
-6225,			// 126
-8291,			// 127
-23243,			// 128
-7838,			// 129
-7073,			// 130
-8935,			// 131
-5437,			// 132
-4483,			// 133
-3641,			// 134
-5256,			// 135
-5312,			// 136
-5328,			// 137
-5370,			// 138
-3492,			// 139
-2458,			// 140
-1694,			// 141
-1821,			// 142
-2121,			// 143
-1916,			// 144
-1149,			// 145
-1516,			// 146
-1367,			// 147
-1236,			// 148
-1029,			// 149
-1258,			// 150
-1104,			// 151
-1245,			// 152
-1006,			// 153
-1149,			// 154
-1025,			// 155
-1241,			// 156
-952,			// 157
-1287,			// 158
-997,			// 159
-1713,			// 160
-1009,			// 161
-1187,			// 162
-879,			// 163
-1099,			// 164
-929,			// 165
-1078,			// 166
-951,			// 167
-1656,			// 168
-930,			// 169
-1153,			// 170
-1030,			// 171
-1262,			// 172
-1062,			// 173
-1214,			// 174
-1060,			// 175
-1621,			// 176
-930,			// 177
-1106,			// 178
-912,			// 179
-1034,			// 180
-892,			// 181
-1158,			// 182
-990,			// 183
-1175,			// 184
-850,			// 185
-1121,			// 186
-903,			// 187
-1087,			// 188
-920,			// 189
-1144,			// 190
-1056,			// 191
-3462,			// 192
-2240,			// 193
-4397,			// 194
-12136,			// 195
-7758,			// 196
-1345,			// 197
-1307,			// 198
-3278,			// 199
-1950,			// 200
-886,			// 201
-1023,			// 202
-1112,			// 203
-1077,			// 204
-1042,			// 205
-1061,			// 206
-1071,			// 207
-1484,			// 208
-1001,			// 209
-1096,			// 210
-915,			// 211
-1052,			// 212
-995,			// 213
-1070,			// 214
-876,			// 215
-1111,			// 216
-851,			// 217
-1059,			// 218
-805,			// 219
-1112,			// 220
-923,			// 221
-1103,			// 222
-817,			// 223
-1899,			// 224
-1872,			// 225
-976,			// 226
-841,			// 227
-1127,			// 228
-956,			// 229
-1159,			// 230
-950,			// 231
-7791,			// 232
-954,			// 233
-1289,			// 234
-933,			// 235
-1127,			// 236
-3207,			// 237
-1020,			// 238
-927,			// 239
-1355,			// 240
-768,			// 241
-1040,			// 242
-745,			// 243
-952,			// 244
-805,			// 245
-1073,			// 246
-740,			// 247
-1013,			// 248
-805,			// 249
-1008,			// 250
-796,			// 251
-996,			// 252
-1057,			// 253
-11457,			// 254
-13504,			// 255
-};
-
-void MSG_initHuffman() {
-	int i,j;
-
-	msgInit = qtrue;
-	Huff_Init(&msgHuff);
-	for(i=0;i<256;i++) {
-		for (j=0;j<msg_hData[i];j++) {
-			Huff_addRef(&msgHuff.compressor,	(byte)i);			// Do update
-			Huff_addRef(&msgHuff.decompressor,	(byte)i);			// Do update
-		}
-	}
-}
-
-/*
-void MSG_NUinitHuffman() {
-	byte	*data;
-	int		size, i, ch;
-	int		array[256];
-
-	msgInit = qtrue;
-
-	Huff_Init(&msgHuff);
-	// load it in
-	size = FS_ReadFile( "netchan/netchan.bin", (void **)&data );
-
-	for(i=0;i<256;i++) {
-		array[i] = 0;
-	}
-	for(i=0;i<size;i++) {
-		ch = data[i];
-		Huff_addRef(&msgHuff.compressor,	ch);			// Do update
-		Huff_addRef(&msgHuff.decompressor,	ch);			// Do update
-		array[ch]++;
-	}
-	Com_Printf("msg_hData {\n");
-	for(i=0;i<256;i++) {
-		if (array[i] == 0) {
-			Huff_addRef(&msgHuff.compressor,	i);			// Do update
-			Huff_addRef(&msgHuff.decompressor,	i);			// Do update
-		}
-		Com_Printf("%d,			// %d\n", array[i], i);
-	}
-	Com_Printf("};\n");
-	FS_FreeFile( data );
-	Cbuf_AddText( "condump dump.txt\n" );
-}
-*/
-
 //===========================================================================
diff -wrubN quake3_1.32b/code/qcommon/qcommon.h dfengine_1.08_src/code/qcommon/qcommon.h
--- quake3_1.32b/code/qcommon/qcommon.h	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/qcommon/qcommon.h	2009-07-22 15:05:49.000000000 +0200
@@ -543,6 +543,7 @@
 // will properly create any needed paths and deal with seperater character issues
 
 int		FS_filelength( fileHandle_t f );
+qboolean FS_SV_FileExists( const char *file );	// Cgg - was missing
 fileHandle_t FS_SV_FOpenFileWrite( const char *filename );
 int		FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );
 void	FS_SV_Rename( const char *from, const char *to );
@@ -627,12 +628,19 @@
 // separated checksums will be checked for files, with the
 // sole exception of .cfg files.
 
-qboolean FS_idPak( char *pak, char *base );
+qboolean FS_idPak( const char *pak, const char *base );
 qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
 
 void FS_Rename( const char *from, const char *to );
 
-// Cgg - autocompletion on map & demo names
+// Cgg
+// return the current gamedir (eg. "baseq3", "mymod"...)
+const char *FS_GetGameDir();
+// remove a file from the homepath (eg. C:\quake3\; ~/.q3a/)
+qboolean FS_SV_RemoveFile(const char *filepath);
+// remove a file from homepath/gamedir (eg. C:\quake3\mymod\; ~/.q3a/mymod)
+qboolean FS_RemoveFile(const char *filename);
+// autocompletion on map & demo names
 void Maps_CommandCompletion(void (*callback) (const char *s));
 void Demos_CommandCompletion(void (*callback) (const char *s));
 // !Cgg
@@ -731,6 +739,7 @@
 extern	cvar_t	*com_buildScript;		// for building release pak files
 extern	cvar_t	*com_journal;
 extern	cvar_t	*com_cameraMode;
+extern	cvar_t	*com_sleepfps;			// Cgg
 
 // both client and server must agree to pause
 extern	cvar_t	*cl_paused;
@@ -1042,28 +1051,21 @@
 	node_t*		loc[HMAX+1];
 	node_t**	freelist;
 
-	node_t		nodeList[768];
-	node_t*		nodePtrs[768];
+	// Cgg - had 768 nodes; while actual max is (256 values + NYT) *2 -1 => 513
+	node_t		nodeList[513];
+	node_t*		nodePtrs[513];
 } huff_t;
 
-typedef struct {
-	huff_t		compressor;
-	huff_t		decompressor;
-} huffman_t;
-
 void	Huff_Compress(msg_t *buf, int offset);
 void	Huff_Decompress(msg_t *buf, int offset);
-void	Huff_Init(huffman_t *huff);
 void	Huff_addRef(huff_t* huff, byte ch);
 int		Huff_Receive (node_t *node, int *ch, byte *fin);
 void	Huff_transmit (huff_t *huff, int ch, byte *fout);
-void	Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset);
-void	Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset);
+void	Huff_offsetReceive (int *ch, byte *fin, int *offset);	// Cgg (changed prototype)
+void	Huff_offsetTransmit (int ch, byte *fout, int *offset);	// Cgg (changed prototype)
 void	Huff_putBit( int bit, byte *fout, int *offset);
 int		Huff_getBit( byte *fout, int *offset);
 
-extern huffman_t clientHuffTables;
-
 #define	SV_ENCODE_START		4
 #define SV_DECODE_START		12
 #define	CL_ENCODE_START		12
diff -wrubN quake3_1.32b/code/renderer/qgl.h dfengine_1.08_src/code/renderer/qgl.h
--- quake3_1.32b/code/renderer/qgl.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/renderer/qgl.h	2009-04-18 19:37:40.000000000 +0200
@@ -90,6 +90,12 @@
 #define GL_TEXTURE2_ARB                     0x84C2
 #define GL_TEXTURE3_ARB                     0x84C3
 
+// marky
+#ifndef GL_EXT_texture_edge_clamp
+#define GL_EXT_CLAMP_TO_EDGE                 0x812F
+#endif
+// !marky
+
 // NOTE: some Linux platforms would need those prototypes
 #if defined(MACOS_X)
 typedef void (APIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
diff -wrubN quake3_1.32b/code/renderer/tr_image.c dfengine_1.08_src/code/renderer/tr_image.c
--- quake3_1.32b/code/renderer/tr_image.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/renderer/tr_image.c	2009-07-12 17:40:21.000000000 +0200
@@ -1431,6 +1431,17 @@
    * with the stdio data source.
    */
 
+	// drakkar - engine only supports RGBA ( 4 bytes per pixel )
+	if( cinfo.output_components != 4 )
+	{
+		*pic = NULL;
+		ri.Printf( PRINT_WARNING, "LoadJPG: illegal bytes per pixel '%d' in file '%s'\n", cinfo.output_components, filename );
+		jpeg_destroy_decompress(&cinfo);
+		ri.FS_FreeFile (fbuffer);
+		return;
+	}
+	// !drakkar
+
   /* We may need to do some setup of our own at this point before reading
    * the data.  After jpeg_start_decompress() we have the correct scaled
    * output image dimensions available, as well as the output colormap
diff -wrubN quake3_1.32b/code/renderer/tr_init.c dfengine_1.08_src/code/renderer/tr_init.c
--- quake3_1.32b/code/renderer/tr_init.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/renderer/tr_init.c	2009-12-31 16:09:29.000000000 +0100
@@ -226,8 +226,10 @@
 	// init command buffers and SMP
 	R_InitCommandBuffers();
 
+	// Cgg - spammy
 	// print info
-	GfxInfo_f();
+	//GfxInfo_f();
+	// !Cgg
 
 	// set default state
 	GL_SetDefaultState();
@@ -384,6 +386,7 @@
 	buffer[15] = height >> 8;
 	buffer[16] = 24;	// pixel size
 
+	qglPixelStorei(GL_PACK_ALIGNMENT, 1); //marky: fixes nonstandard res'
 	qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); 
 
 	// swap rgb to bgr
@@ -847,6 +850,45 @@
 	}
 }
 
+
+// drakkar
+/*
+================
+R_WindowMode_f
+================
+*/
+void R_WindowMode_f( void ) 
+{
+	char *str = NULL;
+
+	str = ri.Cmd_Argv(1);
+	
+	if     ( !strncasecmp( str, "restart",        7 ) )  GLimp_WindowMode( WMODE_RESTART );
+	else if( !strncasecmp( str, "minimized",      3 ) )  GLimp_WindowMode( WMODE_SET_MINIMIZED );
+	else if( !strncasecmp( str, "windowed",       3 ) )  GLimp_WindowMode( WMODE_SET_WINDOWED );
+	else if( !strncasecmp( str, "fullscreen",     4 ) )  GLimp_WindowMode( WMODE_SET_FULLSCREEN );
+	else if( !strncasecmp( str, "swapFullscreen", 8 ) )  GLimp_WindowMode( WMODE_SWAP_FULLSCREEN );
+	else if( !strncasecmp( str, "swapMinimized",  7 ) )  GLimp_WindowMode( WMODE_SWAP_MINIMIZED );
+	else
+	{
+		str = ri.Cmd_Argv(0);
+		ri.Printf( PRINT_ALL,
+			"How to use:\n"
+			"\\%s restart\n"
+			"\\%s minimized\n"
+			"\\%s windowed\n"
+			"\\%s fullscreen\n"
+			"\\%s swapFullscreen\n"
+			"\\%s swapMinimized\n"
+			, str, str, str, str, str, str
+		);
+	}
+
+	Cvar_Get( "in_keyboardShortcuts", "", 0 )->modified = qtrue;
+}
+// !drakkar
+
+
 /*
 ===============
 R_Register
@@ -1003,6 +1045,9 @@
 	ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
 	ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f );
 	ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
+	// drakkar
+	ri.Cmd_AddCommand( "windowMode", R_WindowMode_f );
+	// !drakkar
 }
 
 /*
@@ -1122,6 +1167,9 @@
 	ri.Cmd_RemoveCommand ("gfxinfo");
 	ri.Cmd_RemoveCommand( "modelist" );
 	ri.Cmd_RemoveCommand( "shaderstate" );
+	// drakkar
+	ri.Cmd_RemoveCommand( "windowMode" );
+	// !drakkar
 
 
 	if ( tr.registered ) {
@@ -1213,5 +1261,8 @@
 	re.GetEntityToken = R_GetEntityToken;
 	re.inPVS = R_inPVS;
 
+	// drakkar
+	re.WindowFocus = GLimp_WindowFocus;
+
 	return &re;
 }
diff -wrubN quake3_1.32b/code/renderer/tr_local.h dfengine_1.08_src/code/renderer/tr_local.h
--- quake3_1.32b/code/renderer/tr_local.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/renderer/tr_local.h	2009-06-26 14:53:03.000000000 +0200
@@ -1247,6 +1247,19 @@
 						    unsigned char green[256],
 							unsigned char blue[256] );
 
+// drakkar
+typedef enum {
+	WMODE_RESTART = 0,
+	WMODE_SET_MINIMIZED,
+	WMODE_SET_WINDOWED,
+	WMODE_SET_FULLSCREEN,
+	WMODE_SWAP_FULLSCREEN,
+	WMODE_SWAP_MINIMIZED
+} windowMode_t;
+void GLimp_WindowMode( windowMode_t wmode );
+void GLimp_WindowFocus(qboolean focus);
+// !drakkar
+
 
 /*
 ====================================================================
diff -wrubN quake3_1.32b/code/renderer/tr_public.h dfengine_1.08_src/code/renderer/tr_public.h
--- quake3_1.32b/code/renderer/tr_public.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/renderer/tr_public.h	2009-06-26 14:53:03.000000000 +0200
@@ -97,6 +97,8 @@
 	void	(*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);
 	qboolean (*GetEntityToken)( char *buffer, int size );
 	qboolean (*inPVS)( const vec3_t p1, const vec3_t p2 );
+	// drakkar
+	void (*WindowFocus)(qboolean focus);
 } refexport_t;
 
 //
diff -wrubN quake3_1.32b/code/renderer/tr_shade_calc.c dfengine_1.08_src/code/renderer/tr_shade_calc.c
--- quake3_1.32b/code/renderer/tr_shade_calc.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/renderer/tr_shade_calc.c	2009-12-04 17:54:28.000000000 +0100
@@ -354,12 +354,18 @@
 	float	radius;
 	vec3_t	left, up;
 	vec3_t	leftDir, upDir;
+	static qboolean warn = qfalse;	// Cgg
 
+	// Cgg - gross latch for those warning messages
+	if (!warn) {
 	if ( tess.numVertexes & 3 ) {
-		ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count", tess.shader->name );
+			ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name );
+			warn = qtrue;
 	}
 	if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
-		ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count", tess.shader->name );
+			ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name );
+			warn = qtrue;
+		}
 	}
 
 	oldVerts = tess.numVertexes;
@@ -431,12 +437,18 @@
 	int		indexes;
 	float	*xyz;
 	vec3_t	forward;
+	static qboolean warn = qfalse;	// Cgg
 
+	// Cgg - gross latch for those warning messages
+	if (!warn) {
 	if ( tess.numVertexes & 3 ) {
-		ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name );
+			ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count\n", tess.shader->name );
+			warn = qtrue;
 	}
 	if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
-		ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name );
+			ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count\n", tess.shader->name );
+			warn = qtrue;
+		}
 	}
 
 	if ( backEnd.currentEntity != &tr.worldEntity ) {
diff -wrubN quake3_1.32b/code/renderer/tr_shader.c dfengine_1.08_src/code/renderer/tr_shader.c
--- quake3_1.32b/code/renderer/tr_shader.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/renderer/tr_shader.c	2009-05-26 12:06:05.000000000 +0200
@@ -1227,7 +1227,7 @@
 		for (i=0 ; i<6 ; i++) {
 			Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
 				, token, suf[i] );
-			shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP );
+			shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_EXT_CLAMP_TO_EDGE );	// marky: GL_CLAMP to GL_CLAMP_TO_EDGE
 			if ( !shader.sky.outerbox[i] ) {
 				shader.sky.outerbox[i] = tr.defaultImage;
 			}
@@ -2872,7 +2872,9 @@
 		char filename[MAX_QPATH];
 
 		Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
-		ri.Printf( PRINT_ALL, "...loading '%s'\n", filename );
+// Cgg - spammy and rather pointless - made it PRINT_DEV
+		ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
+// !Cgg
 		sum += ri.FS_ReadFile( filename, (void **)&buffers[i] );
 		if ( !buffers[i] ) {
 			ri.Error( ERR_DROP, "Couldn't load %s", filename );
diff -wrubN quake3_1.32b/code/server/server.h dfengine_1.08_src/code/server/server.h
--- quake3_1.32b/code/server/server.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/server/server.h	2009-10-17 21:07:48.000000000 +0200
@@ -243,6 +243,7 @@
 extern	cvar_t	*sv_floodProtect;
 extern	cvar_t	*sv_lanForceRate;
 extern	cvar_t	*sv_strictAuth;
+extern	cvar_t	*sv_noReferencedPaks;	// uZu - don't set sv_referencedPak{s,Names}
 
 //===========================================================
 
diff -wrubN quake3_1.32b/code/server/sv_client.c dfengine_1.08_src/code/server/sv_client.c
--- quake3_1.32b/code/server/sv_client.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/server/sv_client.c	2009-07-29 01:20:31.000000000 +0200
@@ -241,10 +241,27 @@
 	int			startIndex;
 	char		*denied;
 	int			count;
+	char		k[MAX_INFO_KEY], v[MAX_INFO_VALUE], *c;	// Cgg
 
 	Com_DPrintf ("SVC_DirectConnect ()\n");
 
-	Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
+	// Cgg - prevent bypassing server bans through infostring overflow
+	c = Cmd_Argv(1);
+	userinfo[0] = 0;
+	if (!NET_IsLocalAddress(from)) {
+		Info_SetValueForKey(userinfo, "ip", NET_AdrToString(from));
+	} else {
+		Info_SetValueForKey(userinfo, "ip", "localhost");
+	}
+	while (*c) {
+		Info_NextPair(&c, k, v);
+		if (!stricmp(k, "ip")) {
+			continue;
+		}
+		Info_SetValueForKey(userinfo, k, v);
+	}
+	// Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
+	// !Cgg
 
 	version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
 	if ( version != PROTOCOL_VERSION ) {
@@ -288,8 +305,10 @@
 			NET_OutOfBandPrint( NS_SERVER, from, "print\nNo or bad challenge for address.\n" );
 			return;
 		}
+// Cgg - see above
 		// force the IP key/value pair so the game can filter based on ip
-		Info_SetValueForKey( userinfo, "ip", NET_AdrToString( from ) );
+//		Info_SetValueForKey( userinfo, "ip", NET_AdrToString( from ) );
+// !Cgg
 
 		ping = svs.time - svs.challenges[i].pingTime;
 		Com_Printf( "Client %i connecting with %i challenge ping\n", i, ping );
@@ -313,8 +332,10 @@
 			}
 		}
 	} else {
+// Cgg - see above
 		// force the "ip" info key to "localhost"
-		Info_SetValueForKey( userinfo, "ip", "localhost" );
+//		Info_SetValueForKey( userinfo, "ip", "localhost" );
+// !Cgg
 	}
 
 	newcl = &temp;
diff -wrubN quake3_1.32b/code/server/sv_init.c dfengine_1.08_src/code/server/sv_init.c
--- quake3_1.32b/code/server/sv_init.c	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/server/sv_init.c	2009-10-17 21:07:48.000000000 +0200
@@ -522,14 +522,17 @@
 	}
 // Cgg - this fails with the large number of defrag pk3s
 // Removing this prevents packs from being auto-downloaded, but so does repacking.
-/*
+	if (sv_noReferencedPaks->integer == 0) {	// uZu
 	// the server sends these to the clients so they can figure
 	// out which pk3s should be auto-downloaded
 	p = FS_ReferencedPakChecksums();
 	Cvar_Set( "sv_referencedPaks", p );
 	p = FS_ReferencedPakNames();
 	Cvar_Set( "sv_referencedPakNames", p );
-*/
+	} else {
+		Cvar_Set( "sv_referencedPaks", "" );
+		Cvar_Set( "sv_referencedPakNames", "" );
+	}
 // !Cgg
 
 	// save systeminfo and serverinfo strings
@@ -616,6 +619,8 @@
 	sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM);
 	sv_lanForceRate = Cvar_Get ("sv_lanForceRate", "1", CVAR_ARCHIVE );
 	sv_strictAuth = Cvar_Get ("sv_strictAuth", "1", CVAR_ARCHIVE );
+	// uZu - don't set sv_referencedPak{s,Names}
+	sv_noReferencedPaks = Cvar_Get ("sv_noReferencedPaks", "1", CVAR_ARCHIVE);
 
 	// initialize bot cvars so they are listed and can be set before loading the botlib
 	SV_BotInitCvars();
diff -wrubN quake3_1.32b/code/server/sv_main.c dfengine_1.08_src/code/server/sv_main.c
--- quake3_1.32b/code/server/sv_main.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/server/sv_main.c	2009-10-17 21:07:48.000000000 +0200
@@ -52,6 +52,7 @@
 cvar_t	*sv_floodProtect;
 cvar_t	*sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)
 cvar_t	*sv_strictAuth;
+cvar_t	*sv_noReferencedPaks;	// uZu - don't set sv_referencedPak{s,Names}
 
 /*
 =============================================================================
diff -wrubN quake3_1.32b/code/ui/keycodes.h dfengine_1.08_src/code/ui/keycodes.h
--- quake3_1.32b/code/ui/keycodes.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/ui/keycodes.h	2009-05-25 11:51:16.000000000 +0200
@@ -151,6 +151,11 @@
 	K_AUX15,
 	K_AUX16,
 
+// drakkar
+	K_WIN,
+	K_MENU,
+// !drakkar
+
 	K_LAST_KEY		// this had better be <256!
 } keyNum_t;
 
diff -wrubN quake3_1.32b/code/unix/linux_glimp.c dfengine_1.08_src/code/unix/linux_glimp.c
--- quake3_1.32b/code/unix/linux_glimp.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/unix/linux_glimp.c	2010-01-20 22:52:05.000000000 +0100
@@ -69,7 +69,9 @@
 #include <X11/extensions/xf86dga.h>
 #include <X11/extensions/xf86vmode.h>
 
-#define	WINDOW_CLASS_NAME	"Quake III: Arena"
+// Cgg
+#define	WINDOW_CLASS_NAME Q3_WINDOW_TITLE
+//"Quake III: Arena"
 
 typedef enum
 {
@@ -87,14 +89,18 @@
 static int scrnum;
 static Window win = 0;
 static GLXContext ctx = NULL;
+static XVisualInfo *visinfo = NULL; // drakkar - create once and reuse
 
 // bk001206 - not needed anymore
 // static qboolean autorepeaton = qtrue;
 
 #define KEY_MASK (KeyPressMask | KeyReleaseMask)
-#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
-		    PointerMotionMask | ButtonMotionMask )
-#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
+#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ButtonMotionMask )
+// drakkar
+//- #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
+#define WINDOW_MASK ( VisibilityChangeMask | StructureNotifyMask | FocusChangeMask )
+#define X_MASK ( KEY_MASK | MOUSE_MASK | WINDOW_MASK )
+// /drakkar
 
 static qboolean mouse_avail;
 static qboolean mouse_active = qfalse;
@@ -115,6 +121,8 @@
 cvar_t   *in_joystickDebug = NULL;
 cvar_t   *joy_threshold    = NULL;
 
+cvar_t	*in_keyboardShortcuts = NULL; // drakkar - ignored in linux
+
 cvar_t  *r_allowSoftwareGL;   // don't abort out if the pixelformat claims software
 cvar_t  *r_previousglDriver;
 
@@ -122,11 +130,20 @@
 static int vidmode_MajorVersion = 0, vidmode_MinorVersion = 0; // major and minor of XF86VidExtensions
 
 // gamma value of the X display before we start playing with it
-static XF86VidModeGamma vidmode_InitialGamma;
+static XF86VidModeGamma vidmode_InitialGamma = { -1,-1,-1 };  // drakkar - initialized to nonvalid values
+
+static int win_x = 50, win_y = 50;  // drakkar - initialize window position
 
-static int win_x, win_y;
+// drakkar
+qboolean win_active = qtrue;
+qboolean win_minimized = qfalse;
+static qboolean windowModeLock = qtrue;
+static unsigned long int ignoreFocus = 0;
+static XF86VidModeModeInfo desktopVideoModeInfo = { 0,0,0,0,0,0,0,0,0,0,0,0 };
+static int desktopVideoMode = -1;
+// !drakkar
 
-static XF86VidModeModeInfo **vidmodes;
+static XF86VidModeModeInfo **vidmodes = NULL;  // drakkar - initialized to NULL
 //static int default_dotclock_vidmode; // bk001204 - unused
 static int num_vidmodes;
 static qboolean vidmode_active = qfalse;
@@ -282,6 +299,13 @@
   case XK_Alt_R:  
   case XK_Meta_R: *key = K_ALT;     break;
 
+  // drakkar
+  case XK_Super_L:
+  case XK_Super_R:  *key = K_WIN;     break;
+  
+  case XK_Menu:  *key = K_MENU;     break;
+  // !drakkar
+
   case XK_KP_Begin: *key = K_KP_5;  break;
 
   case XK_Insert:   *key = K_INS; break;
@@ -446,6 +470,19 @@
   XUndefineCursor(dpy, win);
 }
 
+
+// drakkar
+// Sys_MilliSeconds returns CPU usage time,
+// this fuction returns real time milliseconds
+unsigned long int realMilliSeconds() 
+{
+	struct timeval tv;
+	gettimeofday( &tv, NULL );
+	return (unsigned long int)tv.tv_sec*1000 + (unsigned long int)tv.tv_usec/1000;
+}
+// !drakkar
+
+
 // bk001206 - from Ryan's Fakk2
 /**
  * XPending() actually performs a blocking read 
@@ -688,9 +725,30 @@
       break;
 
     case ConfigureNotify :
+		// drakkar - only user actions
+		if( glConfig.isFullscreen ) break;
+		if( win_active ) break;
+		if( event.xcreatewindow.x < 1 ) break;
+		if( event.xcreatewindow.y < 1 ) break;
+		// !drakkar
       win_x = event.xconfigure.x;
       win_y = event.xconfigure.y;
       break;
+	
+	// drakkar
+	case FocusIn:
+		if( ignoreFocus < realMilliSeconds() ) {
+			GLimp_WindowFocus( qtrue );
+			Key_ClearStates();
+		}
+	break;
+	case FocusOut:
+		if( ignoreFocus < realMilliSeconds() ) {
+			GLimp_WindowFocus( qfalse );
+			Key_ClearStates();
+		}
+	break;
+	// !drakkar
     }
   }
 
@@ -753,6 +811,12 @@
   //   the API wasn't changed to avoid breaking other OSes
   float g = Cvar_Get("r_gamma", "1.0", 0)->value;
   XF86VidModeGamma gamma;
+  // drakkar - do not set gamma if window is not focused
+  Window focus;
+  int state;
+  XGetInputFocus( dpy, &focus, &state );
+  if( win != focus ) return;
+  // !drakkar
   assert(glConfig.deviceSupportsGamma);
   gamma.red = g;
   gamma.green = g;
@@ -779,12 +843,14 @@
   // autorepeaton = qfalse; // bk001130 - from cvs1.17 (mkv)
   if (dpy)
   {
+	if( visinfo ) // drakkar
+	  XFree( visinfo );
     if (ctx)
       qglXDestroyContext(dpy, ctx);
     if (win)
       XDestroyWindow(dpy, win);
     if (vidmode_active)
-      XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
+      XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[desktopVideoMode]); // drakkar - replace 0 by desktopVideoMode
     if (glConfig.deviceSupportsGamma)
     {
       XF86VidModeSetGamma(dpy, scrnum, &vidmode_InitialGamma);
@@ -799,6 +865,11 @@
   dpy = NULL;
   win = 0;
   ctx = NULL;
+  // drakkar  
+  visinfo = NULL;
+  if( vidmodes ) XFree( vidmodes );
+  vidmodes = NULL;  
+  // !drakkar  
 
   memset( &glConfig, 0, sizeof( glConfig ) );
   memset( &glState, 0, sizeof( glState ) );
@@ -862,143 +933,60 @@
   return qtrue;
 }
 
-/*
-** GLW_SetMode
-*/
-int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
-{
-  int attrib[] = {
-    GLX_RGBA,         // 0
-    GLX_RED_SIZE, 4,      // 1, 2
-    GLX_GREEN_SIZE, 4,      // 3, 4
-    GLX_BLUE_SIZE, 4,     // 5, 6
-    GLX_DOUBLEBUFFER,     // 7
-    GLX_DEPTH_SIZE, 1,      // 8, 9
-    GLX_STENCIL_SIZE, 1,    // 10, 11
-    None
-  };
-  // these match in the array
-#define ATTR_RED_IDX 2
-#define ATTR_GREEN_IDX 4
-#define ATTR_BLUE_IDX 6
-#define ATTR_DEPTH_IDX 9
-#define ATTR_STENCIL_IDX 11
-  Window root;
-  XVisualInfo *visinfo;
-  XSetWindowAttributes attr;
-  XSizeHints sizehints;
-  unsigned long mask;
-  int colorbits, depthbits, stencilbits;
-  int tcolorbits, tdepthbits, tstencilbits;
-  int dga_MajorVersion, dga_MinorVersion;
-  int actualWidth, actualHeight;
-  int i;
-  const char*   glstring; // bk001130 - from cvs1.17 (mkv)
-
-  ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
 
-  ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
 
-  if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
+// drakkar
+void GLimp_WindowFocus(qboolean focus)
   {
-    ri.Printf( PRINT_ALL, " invalid mode\n" );
-    return RSERR_INVALID_MODE;
-  }
-  ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
+	if( !dpy || !win ) return;
 
-  if (!(dpy = XOpenDisplay(NULL)))
+	if( focus )
   {
-    fprintf(stderr, "Error couldn't open the X display\n");
-    return RSERR_INVALID_MODE;
+		R_SetColorMappings();
+		if( win_minimized )
+			GLimp_WindowMode( WMODE_SWAP_MINIMIZED );
   }
-  
-  scrnum = DefaultScreen(dpy);
-  root = RootWindow(dpy, scrnum);
-
-  actualWidth = glConfig.vidWidth;
-  actualHeight = glConfig.vidHeight;
-
-  // Get video mode list
-  if (!XF86VidModeQueryVersion(dpy, &vidmode_MajorVersion, &vidmode_MinorVersion))
-  {
-    vidmode_ext = qfalse;
-  } else
+	else
   {
-    ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
-              vidmode_MajorVersion, vidmode_MinorVersion);
-    vidmode_ext = qtrue;
+		if( glConfig.deviceSupportsGamma )
+			XF86VidModeSetGamma( dpy, scrnum, &vidmode_InitialGamma );
+		if( glConfig.isFullscreen )
+			GLimp_WindowMode( WMODE_SWAP_MINIMIZED );
   }
 
-  // Check for DGA	
-  dga_MajorVersion = 0, dga_MinorVersion = 0;
-  if (in_dgamouse->value)
-  {
-    if (!XF86DGAQueryVersion(dpy, &dga_MajorVersion, &dga_MinorVersion))
-    {
-      // unable to query, probalby not supported
-      ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
-      ri.Cvar_Set( "in_dgamouse", "0" );
-    } else
-    {
-      ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n",
-                 dga_MajorVersion, dga_MinorVersion);
-    }
+	win_active = ( focus && !win_minimized );
   }
+// !drakkar
 
-  if (vidmode_ext)
-  {
-    int best_fit, best_dist, dist, x, y;
 
-    XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
 
-    // Are we going fullscreen?  If so, let's change video mode
-    if (fullscreen)
-    {
-      best_dist = 9999999;
-      best_fit = -1;
-
-      for (i = 0; i < num_vidmodes; i++)
-      {
-        if (glConfig.vidWidth > vidmodes[i]->hdisplay ||
-            glConfig.vidHeight > vidmodes[i]->vdisplay)
-          continue;
-
-        x = glConfig.vidWidth - vidmodes[i]->hdisplay;
-        y = glConfig.vidHeight - vidmodes[i]->vdisplay;
-        dist = (x * x) + (y * y);
-        if (dist < best_dist)
-        {
-          best_dist = dist;
-          best_fit = i;
-        }
-      }
 
-      if (best_fit != -1)
-      {
-        actualWidth = vidmodes[best_fit]->hdisplay;
-        actualHeight = vidmodes[best_fit]->vdisplay;
 
-        // change to the mode
-        XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
-        vidmode_active = qtrue;
 
-        // Move the viewport to top left
-        XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
 
-        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension Activated at %dx%d\n",
-                  actualWidth, actualHeight);
+#define ATTR_RED_IDX		2
+#define ATTR_GREEN_IDX		4
+#define ATTR_BLUE_IDX		6
+#define ATTR_DEPTH_IDX		9
+#define ATTR_STENCIL_IDX	11
 
-      } else
-      {
-        fullscreen = 0;
-        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: No acceptable modes found\n");
-      }
-    } else
+XVisualInfo * createVisualInfo(Display *dpy, int scrnum)
     {
-      ri.Printf(PRINT_ALL, "XFree86-VidModeExtension:  Ignored on non-fullscreen/Voodoo\n");
-    }
-  }
+  XVisualInfo *visinfo = NULL;
+  int colorbits, depthbits, stencilbits;
+  int tcolorbits, tdepthbits, tstencilbits;
+  int i;
 
+  int attrib[] = {
+    GLX_RGBA,			// 0
+    GLX_RED_SIZE, 4,	// 1, 2
+    GLX_GREEN_SIZE, 4,	// 3, 4
+    GLX_BLUE_SIZE, 4,	// 5, 6
+    GLX_DOUBLEBUFFER,	// 7
+    GLX_DEPTH_SIZE, 1,	// 8, 9
+    GLX_STENCIL_SIZE, 1,// 10, 11
+    None
+  };
 
   if (!r_colorbits->value)
     colorbits = 24;
@@ -1102,53 +1090,254 @@
     break;
   }
 
-  if (!visinfo)
-  {
-    ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
-    return RSERR_INVALID_MODE;
+  return visinfo;
   }
 
-  /* window attributes */
+
+
+Window createWindow(Display *dpy, int scrnum, Window root, XVisualInfo *visinfo, qboolean fullscreen, int x, int y)
+{
+	XSetWindowAttributes attr;
+	XSizeHints sizehints;
+	unsigned long mask;
+	Window win;
+	
   attr.background_pixel = BlackPixel(dpy, scrnum);
   attr.border_pixel = 0;
   attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+	attr.backing_store = NotUseful;
+	attr.save_under = False;
   attr.event_mask = X_MASK;
-  if (vidmode_active)
+	mask = CWEventMask | CWBackPixel | CWBorderPixel | CWColormap | CWBackingStore | CWSaveUnder;
+
+  	if( fullscreen )
   {
-    mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | 
-           CWEventMask | CWOverrideRedirect;
+		mask |= CWOverrideRedirect;
     attr.override_redirect = True;
-    attr.backing_store = NotUseful;
-    attr.save_under = False;
-  } else
-    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+		x = 0;
+		y = 0;
+	}
 
-  win = XCreateWindow(dpy, root, 0, 0, 
-                      actualWidth, actualHeight, 
+	win = XCreateWindow( dpy, root,
+						 x, y,  glConfig.vidWidth, glConfig.vidHeight, 
                       0, visinfo->depth, InputOutput,
                       visinfo->visual, mask, &attr);
-
+	if( !win ) return 0;
   XStoreName( dpy, win, WINDOW_CLASS_NAME );
 
-  /* GH: Don't let the window be resized */
-  sizehints.flags = PMinSize | PMaxSize;
-  sizehints.min_width = sizehints.max_width = actualWidth;
-  sizehints.min_height = sizehints.max_height = actualHeight;
+	XMapWindow( dpy, win );	
+	XFlush(dpy);
 
+	XMoveWindow( dpy, win, x, y );
+
+	// GH: Don't let the window be resized
+	sizehints.flags = PMinSize | PMaxSize;
+	sizehints.min_width = sizehints.max_width = glConfig.vidWidth;
+	sizehints.min_height = sizehints.max_height = glConfig.vidHeight;
   XSetWMNormalHints( dpy, win, &sizehints );
 
-  XMapWindow( dpy, win );
+	XFlush(dpy);
 
-  if (vidmode_active)
-    XMoveWindow(dpy, win, 0, 0);
+	return win;
+}
 
-  XFlush(dpy);
+
+qboolean switchToMode(Display *dpy, int scrnum, qboolean fullscreen)
+{
+  if (!XF86VidModeQueryVersion(dpy, &vidmode_MajorVersion, &vidmode_MinorVersion))
+  {
+    vidmode_ext = qfalse;
+	// drakkar
+	fullscreen = qfalse;
+	vidmode_active = qfalse;
+	// !drakkar
+  } else
+  {
+    ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
+              vidmode_MajorVersion, vidmode_MinorVersion);
+    vidmode_ext = qtrue;
+  }
+  
+  if (vidmode_ext)
+  {
+    int best_fit, best_dist, dist, x, y, i;
+
+	if( vidmodes ) XFree( vidmodes ); // drakkar
+	XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
+
+	// drakkar
+	// search desktop video mode:
+	// first time vidmodes[0] is always the desktop video mode ( we come from desktop )
+	// but vidmodes[0] is not always the desktop video mode in some graphic card drivers
+	if( desktopVideoModeInfo.hdisplay == 0 ) // first time, desktop mode = vidmodes[0]
+	{
+		desktopVideoModeInfo = *vidmodes[0];
+		desktopVideoMode = 0;
+	}
+	else // desktop mode = one in vidmodes array, normally vidmodes[0]
+	{
+		desktopVideoMode = 0;
+		for( i = 0; i < num_vidmodes; i++ )
+		{
+			dist = memcmp( vidmodes[i], &desktopVideoModeInfo, sizeof(*vidmodes[i])-sizeof(vidmodes[i]->private) );
+			if( !dist )
+			{
+				desktopVideoMode = i;
+				break;
+			}
+		}
+	}
+	// !drakkar
+
+    // Are we going fullscreen?  If so, let's change video mode
+    if (fullscreen)
+    {
+      best_dist = 9999999;
+      best_fit = -1;
+
+      for (i = 0; i < num_vidmodes; i++)
+      {
+        if (glConfig.vidWidth  > vidmodes[i]->hdisplay || glConfig.vidHeight > vidmodes[i]->vdisplay)
+          continue;
+
+        x = glConfig.vidWidth  - vidmodes[i]->hdisplay;
+        y = glConfig.vidHeight - vidmodes[i]->vdisplay;
+        dist = (x * x) + (y * y);
+        if (dist < best_dist)
+        {
+          best_dist = dist;
+          best_fit = i;
+        }
+      }
+
+      if (best_fit != -1)
+      {
+        glConfig.vidWidth  = vidmodes[best_fit]->hdisplay;
+        glConfig.vidHeight = vidmodes[best_fit]->vdisplay;
+
+        // change to the mode
+        XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
+		XFlush( dpy );  // drakkar - man 3 XF86VidModeSwitchToMode 
+        vidmode_active = qtrue;
+        // Move the viewport to top left
+		if( win ) XMoveWindow( dpy, win, 0, 0 ); // drakkar - XF86VidModeSetViewPort problems if windows is placed out of screen
+        XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
+
+        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension Activated at %dx%d\n", glConfig.vidWidth, glConfig.vidHeight);
+
+      } else
+      {
+        fullscreen = 0;
+        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: No acceptable modes found\n");
+      }
+    }
+	// drakkar	
+//- else
+//- {
+//-   ri.Printf(PRINT_ALL, "XFree86-VidModeExtension:  Ignored on non-fullscreen/Voodoo\n");
+//- }
+	
+	if( !fullscreen )
+    {
+		vidmode_active = qfalse;
+		XF86VidModeSwitchToMode( dpy, scrnum, vidmodes[desktopVideoMode] );
+		ri.Printf(PRINT_ALL, "XFree86-VidModeExtension:  No fullscreen\n");
+    }
+	// !drakkar
+  }
+	
+	glConfig.isFullscreen = fullscreen;
+
+	return fullscreen;
+}
+
+
+/*
+** GLW_SetMode
+*/
+int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
+{  
+  int dga_MajorVersion, dga_MinorVersion;
+  const char*   glstring; // bk001130 - from cvs1.17 (mkv)
+  Window root = 0;
+
+
+  ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
+
+  ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
+
+  if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
+  {
+    ri.Printf( PRINT_ALL, " invalid mode\n" );
+    return RSERR_INVALID_MODE;
+  }
+  ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
+
+	if( !dpy ) // drakkar - skip if display already opened
+	{
+		dpy = XOpenDisplay( NULL );
+		if( !dpy )
+		{
+			fprintf(stderr, "Error couldn't open the X display\n");
+			return RSERR_INVALID_MODE;
+		}
+	}  
+  
+  scrnum = DefaultScreen(dpy);
+  root = RootWindow(dpy, scrnum);
+
+  // Check for DGA	
+  dga_MajorVersion = 0, dga_MinorVersion = 0;
+  if (in_dgamouse->value)
+  {
+    if (!XF86DGAQueryVersion(dpy, &dga_MajorVersion, &dga_MinorVersion))
+    {
+      // unable to query, probalby not supported
+      ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
+      ri.Cvar_Set( "in_dgamouse", "0" );
+    } else
+    {
+      ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n",
+                 dga_MajorVersion, dga_MinorVersion);
+    }
+  }
+
+	// drakkar
+	// moved some code to switchToMode function
+	fullscreen = switchToMode( dpy, scrnum, fullscreen );
+	win_minimized = qfalse;
+
+	// moved visual info code to createVisualInfo function
+	if( !visinfo )
+	{
+		visinfo = createVisualInfo( dpy, scrnum );
+		if( !visinfo )
+		{
+			ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
+			return RSERR_INVALID_MODE;
+		}
+	}
+	
+	// moved window code to createWindow function
+	IN_DeactivateMouse();
+	ignoreFocus = 10000 + realMilliSeconds();
+	if( win ) XDestroyWindow( dpy, win );
+	win = createWindow( dpy, scrnum, root, visinfo, fullscreen, win_x, win_y );
+	if( !win )
+	{
+		ri.Printf( PRINT_ALL, "Couldn't create the window\n" );
+		return RSERR_INVALID_MODE;
+	}
+	IN_ActivateMouse();
+	ignoreFocus = 500 + realMilliSeconds();
+	// !drakkar
+
+	if( !ctx )  // drakkar - skip if context already created
+	{
   XSync(dpy,False); // bk001130 - from cvs1.17 (mkv)
   ctx = qglXCreateContext(dpy, visinfo, NULL, True);
   XSync(dpy,False); // bk001130 - from cvs1.17 (mkv)
-
-  /* GH: Free the visinfo after we're done with it */
-  XFree( visinfo );
+	}
 
   qglXMakeCurrent(dpy, win, ctx);
 
@@ -1180,6 +1369,7 @@
   return RSERR_OK;
 }
 
+
 /*
 ** GLW_InitExtensions
 */
@@ -1303,6 +1493,7 @@
       ri.Printf( PRINT_ALL, "XF86 Gamma extension not supported in this version\n");
       return;
     }
+	if( vidmode_InitialGamma.red < 0 ) // drakkar - get initial gamma only one time
     XF86VidModeGetGamma(dpy, scrnum, &vidmode_InitialGamma);
     ri.Printf( PRINT_ALL, "XF86 Gamma extension initialized\n");
     glConfig.deviceSupportsGamma = qtrue;
@@ -1334,6 +1525,10 @@
   {
     fullscreen = r_fullscreen->integer;
 
+	// drakkar
+	windowModeLock = qfalse;
+	// !drakkar
+	  
     // create the window and set up the context
     if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) )
     {
@@ -1347,6 +1542,10 @@
         goto fail;
     }
 
+	// drakkar
+	windowModeLock = qtrue;
+	// !drakkar
+
     return qtrue;
   } else
   {
@@ -1377,6 +1576,81 @@
   return 0;
 }
 
+
+// drakkar
+/*
+** GLimp_WindowMode
+**
+** Changes window mode ( minimized, windowed, fullscreen ) without vid_restart.
+*/
+void GLimp_WindowMode( windowMode_t wmode )
+{
+	if( !windowModeLock ) return;
+
+	switch( wmode )
+	{
+		case WMODE_SET_MINIMIZED:
+			windowModeLock = qfalse;
+			GLW_StartDriverAndSetMode( r_glDriver->string, r_mode->integer, qfalse );
+			XIconifyWindow( dpy, win, scrnum );
+			win_minimized = qtrue;
+			GLimp_WindowFocus( qfalse );
+			windowModeLock = qtrue;
+		break;
+		
+		case WMODE_SET_WINDOWED:
+			windowModeLock = qfalse;
+			GLW_StartDriverAndSetMode( r_glDriver->string, r_mode->integer, qfalse );
+			win_minimized = qfalse;
+			GLimp_WindowFocus( qtrue );
+			uninstall_grabs();
+			install_grabs();
+			windowModeLock = qtrue;
+			ri.Cvar_Set( "r_fullscreen", "0" );
+			if( glConfig.isFullscreen )
+				Cbuf_AddText( "vid_restart\n" );
+		break;
+		
+		case WMODE_SET_FULLSCREEN:
+			windowModeLock = qfalse;
+			GLW_StartDriverAndSetMode( r_glDriver->string, r_mode->integer, qtrue );
+			win_minimized = qfalse;
+			GLimp_WindowFocus( qtrue );
+			windowModeLock = qtrue;
+			ri.Cvar_Set( "r_fullscreen", "1" );
+			if( !glConfig.isFullscreen )
+				Cbuf_AddText( "vid_restart\n" );
+		break;
+		
+		case WMODE_RESTART:
+			if( r_fullscreen->modified && r_fullscreen->latchedString )
+			{
+				if( !Q_strncmp( r_fullscreen->latchedString, "0", 1 ) )
+					GLimp_WindowMode( WMODE_SET_WINDOWED );
+				else
+					GLimp_WindowMode( WMODE_SET_FULLSCREEN );
+			}
+			else
+			{
+				GLimp_WindowMode( r_fullscreen->integer ? WMODE_SET_FULLSCREEN : WMODE_SET_WINDOWED );
+			}
+		break;
+		
+		case WMODE_SWAP_FULLSCREEN:
+			GLimp_WindowMode( glConfig.isFullscreen ? WMODE_SET_WINDOWED : WMODE_SET_FULLSCREEN );
+		break;		
+		
+		case WMODE_SWAP_MINIMIZED:
+			GLimp_WindowMode( win_minimized ? WMODE_RESTART : WMODE_SET_MINIMIZED );
+		break;
+		
+		default:
+			Com_Printf( "Invalid Window Mode\n" );
+	}
+}
+// !drakkar
+
+
 /*
 ** GLimp_Init
 **
@@ -1721,6 +1995,8 @@
   in_joystickDebug = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP);
   joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE); // FIXME: in_joythreshold
 
+  in_keyboardShortcuts = Cvar_Get ("in_keyboardShortcuts", "0", CVAR_TEMP);  // drakkar - not used in linux
+	
   if (in_mouse->value)
     mouse_avail = qtrue;
   else
@@ -1753,7 +2029,13 @@
     }
   }
 
+	// drakkar
+//-  IN_ActivateMouse();
+	if( win_active )
   IN_ActivateMouse();
+	else
+		IN_DeactivateMouse();
+	// !drakkar
 }
 
 void IN_Activate(void)
diff -wrubN quake3_1.32b/code/unix/linux_local.h dfengine_1.08_src/code/unix/linux_local.h
--- quake3_1.32b/code/unix/linux_local.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/unix/linux_local.h	2009-12-31 16:09:29.000000000 +0100
@@ -47,3 +47,10 @@
 
 // signals.c
 void InitSig(void);
+
+
+// drakkar - main need this to do sleep() if window not active
+extern qboolean win_active;
+extern qboolean win_minimized;
+// !drakkar
+
diff -wrubN quake3_1.32b/code/unix/unix_main.c dfengine_1.08_src/code/unix/unix_main.c
--- quake3_1.32b/code/unix/unix_main.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/unix/unix_main.c	2009-12-31 16:09:29.000000000 +0100
@@ -1267,7 +1267,22 @@
   {
 #ifdef __linux__
     Sys_ConfigureFPU();
-#endif
+#ifndef DEDICATED
+	// drakkar
+	if( win_minimized )
+ 	{
+ 		usleep( 100000 );  // 10 fps, free CPU
+ 	}
+	else if ( !win_active && com_sleepfps->integer )
+	{
+		if (com_sleepfps->integer < 5) {
+			Cvar_Set("com_sleepfps", "5");
+		}
+		usleep( 1000000 / com_sleepfps->integer );
+	}
+ 	// !drakkar
+#endif	// !DEDICATED
+#endif	// __linux__
     Com_Frame ();
   }
 }
diff -wrubN quake3_1.32b/code/win32/win_gamma.c dfengine_1.08_src/code/win32/win_gamma.c
--- quake3_1.32b/code/win32/win_gamma.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/win32/win_gamma.c	2009-12-31 16:09:29.000000000 +0100
@@ -140,6 +140,10 @@
 		return;
 	}
 
+	if( g_wv.hWnd != GetFocus() ) { // drakkar - do not set gamma if window is not focused
+		return;
+	}
+
 //mapGammaMax();
 
 	for ( i = 0; i < 256; i++ ) {
diff -wrubN quake3_1.32b/code/win32/win_glimp.c dfengine_1.08_src/code/win32/win_glimp.c
--- quake3_1.32b/code/win32/win_glimp.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/win32/win_glimp.c	2009-12-31 16:09:29.000000000 +0100
@@ -67,6 +67,10 @@
 
 static qboolean s_classRegistered = qfalse;
 
+// drakkar
+static qboolean windowModeLock = qtrue;
+// !drakkar
+
 //
 // function declaration
 //
@@ -568,12 +572,16 @@
 	return qtrue;
 }
 
+
 /*
 ** GLW_CreateWindow
 **
 ** Responsible for creating the Win32 window and initializing the OpenGL driver.
 */
+// drakkar - some changes to allow swap between fullscreen and windowed
 #define	WINDOW_STYLE	(WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE)
+#define WINDOW_STYLE_NORMAL     (WINDOW_STYLE|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX)
+#define WINDOW_STYLE_FULLSCREEN (WS_POPUP|WS_VISIBLE|WS_SYSMENU|WS_MAXIMIZE)
 static qboolean GLW_CreateWindow( const char *drivername, int width, int height, int colorbits, qboolean cdsFullscreen )
 {
 	RECT			r;
@@ -582,9 +590,7 @@
 	int				x, y, w, h;
 	int				exstyle;
 
-	//
 	// register the window class if necessary
-	//
 	if ( !s_classRegistered )
 	{
 		WNDCLASS wc;
@@ -610,35 +616,31 @@
 		ri.Printf( PRINT_ALL, "...registered window class\n" );
 	}
 
-	//
-	// create the HWND if one does not already exist
-	//
-	if ( !g_wv.hWnd )
-	{
-		//
-		// compute width and height
-		//
-		r.left = 0;
-		r.top = 0;
-		r.right  = width;
-		r.bottom = height;
+	cdsFullscreen = ( cdsFullscreen || !Q_stricmp( _3DFX_DRIVER_NAME, drivername ) );
+	g_wv.isMinimized = qfalse;
 
-		if ( cdsFullscreen || !Q_stricmp( _3DFX_DRIVER_NAME, drivername ) )
+	if( cdsFullscreen )
 		{
 			exstyle = WS_EX_TOPMOST;
-			stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
+		stylebits = WINDOW_STYLE_FULLSCREEN;
 		}
 		else
 		{
 			exstyle = 0;
-			stylebits = WINDOW_STYLE|WS_SYSMENU;
-			AdjustWindowRect (&r, stylebits, FALSE);
+		stylebits = WINDOW_STYLE_NORMAL;
 		}
 
+	r.left = 0;
+	r.top = 0;
+	r.right  = width;
+	r.bottom = height;
+
+	AdjustWindowRect( &r, stylebits, FALSE );
+
 		w = r.right - r.left;
 		h = r.bottom - r.top;
 
-		if ( cdsFullscreen || !Q_stricmp( _3DFX_DRIVER_NAME, drivername ) )
+	if ( cdsFullscreen )
 		{
 			x = 0;
 			y = 0;
@@ -652,13 +654,10 @@
 
 			// adjust window coordinates if necessary 
 			// so that the window is completely on screen
-			if ( x < 0 )
-				x = 0;
-			if ( y < 0 )
-				y = 0;
+		if ( x < 0 ) x = 0;
+		if ( y < 0 ) y = 0;
 
-			if ( w < glw_state.desktopWidth &&
-				 h < glw_state.desktopHeight )
+		if ( w < glw_state.desktopWidth && h < glw_state.desktopHeight )
 			{
 				if ( x + w > glw_state.desktopWidth )
 					x = ( glw_state.desktopWidth - w );
@@ -667,10 +666,13 @@
 			}
 		}
 
+	// create the HWND if one does not already exist
+	if ( !g_wv.hWnd )
+	{
 		g_wv.hWnd = CreateWindowEx (
 			 exstyle, 
 			 WINDOW_CLASS_NAME,
-			 "Quake 3: Arena",
+			 Q3_WINDOW_TITLE,
 			 stylebits,
 			 x, y, w, h,
 			 NULL,
@@ -683,15 +685,19 @@
 			ri.Error (ERR_FATAL, "GLW_CreateWindow() - Couldn't create window");
 		}
 	
-		ShowWindow( g_wv.hWnd, SW_SHOW );
-		UpdateWindow( g_wv.hWnd );
 		ri.Printf( PRINT_ALL, "...created window@%d,%d (%dx%d)\n", x, y, w, h );
 	}
 	else
 	{
 		ri.Printf( PRINT_ALL, "...window already present, CreateWindowEx skipped\n" );
+		SetWindowLong( g_wv.hWnd, GWL_STYLE, stylebits );
+		SetWindowLong( g_wv.hWnd, GWL_EXSTYLE, exstyle );
+		SetWindowPos( g_wv.hWnd, cdsFullscreen?HWND_TOPMOST:HWND_NOTOPMOST, x,y, w,h, SWP_SHOWWINDOW );
 	}
 
+	ShowWindow( g_wv.hWnd, SW_SHOW );
+	UpdateWindow( g_wv.hWnd );
+
 	if ( !GLW_InitDriver( drivername, colorbits ) )
 	{
 		ShowWindow( g_wv.hWnd, SW_HIDE );
@@ -707,6 +713,34 @@
 	return qtrue;
 }
 
+
+
+// drakkar
+void GLimp_WindowFocus(qboolean focus)
+{
+	if( !g_wv.hWnd ) return;
+
+	if( focus )
+	{
+		// Cgg - sets gamma correction, I believe this is not needed when quake hasn't got focus
+		R_SetColorMappings();
+		if( g_wv.isMinimized )
+			GLimp_WindowMode( WMODE_SWAP_MINIMIZED );
+	}
+	else
+	{
+		WG_RestoreGamma();
+		if( glConfig.isFullscreen )
+			GLimp_WindowMode( WMODE_SWAP_MINIMIZED );
+	}
+
+	g_wv.activeApp = ( focus && !g_wv.isMinimized );
+
+	Cvar_Get( "in_keyboardShortcuts", "", 0 )->modified = qtrue;
+}
+// !drakkar
+
+
 static void PrintCDSError( int value )
 {
 	switch ( value )
@@ -1201,6 +1235,10 @@
 	{
 		cdsFullscreen = r_fullscreen->integer;
 
+		// drakkar
+		windowModeLock = qfalse;
+		// !drakkar
+
 		// create the window and set up the context
 		if ( !GLW_StartDriverAndSetMode( drivername, r_mode->integer, r_colorbits->integer, cdsFullscreen ) )
 		{
@@ -1229,6 +1267,10 @@
 			glConfig.isFullscreen = qtrue;
 		}
 
+		// drakkar
+		windowModeLock = qtrue;
+		// !drakkar
+
 		return qtrue;
 	}
 fail:
@@ -1337,6 +1379,84 @@
 	}
 }
 
+
+// drakkar
+/*
+** GLimp_WindowMode
+**
+** Changes window mode ( minimized, windowed, fullscreen ) without vid_restart.
+*/
+void GLimp_WindowMode( windowMode_t wmode )
+{
+	if( !windowModeLock )	return;	
+
+	Cvar_Get( "in_keyboardShortcuts", "", 0 )->modified = qtrue;
+
+	switch( wmode )
+	{
+		case WMODE_SET_MINIMIZED:
+			windowModeLock = qfalse;
+			glw_state.cdsFullscreen = qfalse;
+			ChangeDisplaySettings( 0, 0 );
+			ShowWindow( g_wv.hWnd, SW_SHOWMINIMIZED );			
+			g_wv.isMinimized = qtrue;
+			GLimp_WindowFocus( qfalse );
+			windowModeLock = qtrue;
+		break;
+		
+		case WMODE_SET_WINDOWED:
+			windowModeLock = qfalse;
+			GLW_StartDriverAndSetMode( r_glDriver->string, r_mode->integer, r_colorbits->integer, qfalse );
+			ShowWindow( g_wv.hWnd, SW_SHOWNORMAL );
+			g_wv.isMinimized = qfalse;
+			GLimp_WindowFocus( qtrue );
+			windowModeLock = qtrue;
+			ri.Cvar_Set( "r_fullscreen", "0" );
+			if( glConfig.isFullscreen )
+				Cbuf_AddText( "vid_restart\n" );
+		break;
+		
+		case WMODE_SET_FULLSCREEN:
+			windowModeLock = qfalse;
+			GLW_StartDriverAndSetMode( r_glDriver->string, r_mode->integer, r_colorbits->integer, qtrue );
+			ShowWindow( g_wv.hWnd, SW_SHOWMAXIMIZED );				
+			g_wv.isMinimized = qfalse;
+			GLimp_WindowFocus( qtrue );
+			windowModeLock = qtrue;
+			ri.Cvar_Set( "r_fullscreen", "1" );
+			if( !glConfig.isFullscreen )
+				Cbuf_AddText( "vid_restart\n" );
+		break;
+		
+		case WMODE_RESTART:
+			if( r_fullscreen->modified && r_fullscreen->latchedString )
+			{
+				if( !Q_strncmp( r_fullscreen->latchedString, "0", 1 ) )
+					GLimp_WindowMode( WMODE_SET_WINDOWED );
+				else
+					GLimp_WindowMode( WMODE_SET_FULLSCREEN );
+			}
+			else
+			{
+				GLimp_WindowMode( r_fullscreen->integer ? WMODE_SET_FULLSCREEN : WMODE_SET_WINDOWED );
+			}
+		break;
+		
+		case WMODE_SWAP_FULLSCREEN:
+			GLimp_WindowMode( glConfig.isFullscreen ? WMODE_SET_WINDOWED : WMODE_SET_FULLSCREEN );
+		break;		
+		
+		case WMODE_SWAP_MINIMIZED:
+			GLimp_WindowMode( g_wv.isMinimized ? WMODE_RESTART : WMODE_SET_MINIMIZED );
+		break;
+		
+		default:
+			Com_Printf( "Invalid Window Mode\n" );
+	}
+}
+// !drakkar
+
+
 /*
 ** GLimp_Init
 **
diff -wrubN quake3_1.32b/code/win32/win_input.c dfengine_1.08_src/code/win32/win_input.c
--- quake3_1.32b/code/win32/win_input.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/win32/win_input.c	2009-12-31 16:09:29.000000000 +0100
@@ -32,6 +32,7 @@
 	qboolean	mouseActive;
 	qboolean	mouseInitialized;
   qboolean  mouseStartupDelayed; // delay mouse init to try DI again when we have a window
+	qboolean	mouseRaw;	// Cgg - raw input
 } WinMouseVars_t;
 
 static WinMouseVars_t s_wmv;
@@ -87,7 +88,9 @@
 cvar_t	*in_debugJoystick;
 cvar_t	*joy_threshold;
 
-qboolean	in_appactive;
+// drakkar
+cvar_t	*in_keyboardShortcuts;	// 0: always off, 1: always on, 2: on/off if console is down/up, 3: on/off if windowed/fullscreen
+// !drakkar
 
 // forward-referenced functions
 void IN_StartupJoystick (void);
@@ -187,6 +190,48 @@
 /*
 ============================================================
 
+RAW INPUT MOUSE
+(Cgg)
+
+============================================================
+*/
+qboolean IN_InitRawMouse() {
+	// http://www.usb.org/developers/devclass_docs/Hut1_12.pdf
+	RAWINPUTDEVICE dev = {
+		1,	// usUsagePage - generic desktop controls
+		2,	// usUsage - mouse
+		0,	// dwFlags
+		0	// hwndTarget
+	};
+	if (!RegisterRawInputDevices(&dev, 1, sizeof(dev))) {
+		Com_Printf("Raw input registration failed. (0x%x)\n", GetLastError());
+		return qfalse;
+	}
+	Com_Printf("Registered for raw input.\n");
+	s_wmv.mouseRaw = qtrue;
+	return qtrue;
+}
+
+void IN_ShutdownRawMouse() {
+	RAWINPUTDEVICE dev = {
+		1,	// usUsagePage - generic desktop controls
+		2,	// usUsage - mouse
+		RIDEV_REMOVE,	// dwFlags
+		0	// hwndTarget
+	};
+	s_wmv.mouseRaw = qfalse;
+	if (!RegisterRawInputDevices(&dev, 1, sizeof(dev))) {
+		Com_Printf("Mouse release failed. (0x%x)\n", GetLastError());
+	}
+}
+
+qboolean IN_RawMouseActive() {
+	return s_wmv.mouseActive && s_wmv.mouseRaw;
+}
+
+/*
+============================================================
+
 DIRECT INPUT MOUSE CONTROL
 
 ============================================================
@@ -288,6 +333,8 @@
 		}
 	}
 
+	if( !g_pdi ) // drakkar
+	{
 	// register with DirectInput and get an IDirectInput to play with.
 	hr = iDirectInputCreate( g_wv.hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
 
@@ -295,7 +342,10 @@
 		Com_Printf ("iDirectInputCreate failed\n");
 		return qfalse;
 	}
+	}
 
+	if( !g_pMouse ) // drakkar
+	{
 	// obtain an interface to the system mouse device.
 	hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
 
@@ -303,6 +353,7 @@
 		Com_Printf ("Couldn't open DI mouse device\n");
 		return qfalse;
 	}
+	}
 
 	// set the data format to "mouse format".
 	hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df);
@@ -417,6 +468,9 @@
 		hr = IDirectInputDevice_GetDeviceData(g_pMouse,
 				sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
 		if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
+			// drakkar - vid_restart creates a new window, so we have a new window handle ( hWnd )
+			IDirectInputDevice_SetCooperativeLevel( g_pMouse, g_wv.hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND );
+			// !drakkar
 			IDirectInputDevice_Acquire(g_pMouse);
 			return;
 		}
@@ -571,10 +625,15 @@
 	}
 
 	if ( in_mouse->integer == -1 ) {
-		Com_Printf ("Skipping check for DirectInput\n");
+		Com_Printf ("Skipping check for DirectInput and Raw Input\n");
+	} else if (in_mouse->integer == 3) {	// Cgg - raw input
+		if (IN_InitRawMouse()) {
+			s_wmv.mouseInitialized = qtrue;
+			return;
+		}
+		Com_Printf ("Falling back to Win32 mouse support...\n");
 	} else {
-    if (!g_wv.hWnd)
-    {
+		if (!g_wv.hWnd) {
       Com_Printf ("No window for DirectInput mouse init, delaying\n");
       s_wmv.mouseStartupDelayed = qtrue;
       return;
@@ -629,7 +688,15 @@
 void IN_MouseMove ( void ) {
 	int		mx, my;
 
+	// Cgg - raw input is based on wndproc events - not frames.
+	if ( s_wmv.mouseRaw ) {
+		// keep the windows cursor centered
+		SetCursorPos(window_center_x, window_center_y);
+		return;
+	}
+	// !Cgg
 	if ( g_pMouse ) {
+		mx = my = 0; // drakkar - IN_DIMouse can return without set values
 		IN_DIMouse( &mx, &my );
 	} else {
 		IN_Win32Mouse( &mx, &my );
@@ -642,6 +709,36 @@
 	Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
 }
 
+/*
+============================================================
+
+  KEYBOARD CONTROL
+
+============================================================
+*/
+
+// drakkar
+void IN_UpdateKeyboardShortcuts( void )
+{
+	int mode, enable = 1;
+
+	mode = in_keyboardShortcuts->integer;
+
+	if		( mode == 0 ) enable = 0;
+	else if	( mode == 1 ) enable = 1;
+	else if	( mode == 2 ) enable = ( cls.keyCatchers & KEYCATCH_CONSOLE ? 1 : 0 );
+	else if	( mode == 3 ) enable = !Cvar_VariableIntegerValue( "r_fullscreen" );
+	else
+	{
+		Com_Printf( "Invalid in_keyboardShortcuts value\n" );
+		Cvar_Reset( "in_keyboardShortcuts" );
+		return;
+	}
+
+	EnableKeyboardShortcuts( enable );
+}
+// !drakkar
+
 
 /*
 =========================================================================
@@ -673,6 +770,7 @@
 void IN_Shutdown( void ) {
 	IN_DeactivateMouse();
 	IN_ShutdownDIMouse();
+	IN_ShutdownRawMouse();
 	IN_ShutdownMIDI();
 	Cmd_RemoveCommand("midiinfo" );
 }
@@ -703,28 +801,12 @@
 
 	joy_threshold			= Cvar_Get ("joy_threshold",			"0.15",		CVAR_ARCHIVE);
 
+	in_keyboardShortcuts    = Cvar_Get ("in_keyboardShortcuts",		"2",	CVAR_ARCHIVE); // drakkar
+
 	IN_Startup();
 }
 
 
-/*
-===========
-IN_Activate
-
-Called when the main window gains or loses focus.
-The window may have been destroyed and recreated
-between a deactivate and an activate.
-===========
-*/
-void IN_Activate (qboolean active) {
-	in_appactive = active;
-
-	if ( !active )
-	{
-		IN_DeactivateMouse();
-	}
-}
-
 
 /*
 ==================
@@ -747,6 +829,13 @@
 		return;
 	}
 
+	// drakkar
+	if( in_keyboardShortcuts->modified ) {
+		in_keyboardShortcuts->modified = qfalse;
+		IN_UpdateKeyboardShortcuts();
+	}
+	// !drakkar
+
 	if ( cls.keyCatchers & KEYCATCH_CONSOLE ) {
 		// temporarily deactivate if not in the game and
 		// running on the desktop
@@ -758,7 +847,7 @@
 		}
 	}
 
-	if ( !in_appactive ) {
+	if ( !g_wv.activeApp ) { // drakkar - changed 'in_appactive' by 'g_wv.activeApp' ( 'in_appactive' was deleted )
 		IN_DeactivateMouse ();
 		return;
 	}
diff -wrubN quake3_1.32b/code/win32/win_local.h dfengine_1.08_src/code/win32/win_local.h
--- quake3_1.32b/code/win32/win_local.h	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/win32/win_local.h	2009-06-26 14:53:03.000000000 +0200
@@ -60,9 +60,10 @@
 
 void	IN_DeactivateWin32Mouse( void);
 
-void	IN_Activate (qboolean active);
 void	IN_Frame (void);
 
+qboolean IN_RawMouseActive(); // Cgg
+
 // window procedure
 LONG WINAPI MainWndProc (
     HWND    hWnd,
@@ -75,6 +76,10 @@
 void SNDDMA_Activate( void );
 int  SNDDMA_InitDS ();
 
+// drakkar
+void EnableKeyboardShortcuts(qboolean enable);
+// !drakkar
+
 typedef struct
 {
 	
diff -wrubN quake3_1.32b/code/win32/win_main.c dfengine_1.08_src/code/win32/win_main.c
--- quake3_1.32b/code/win32/win_main.c	2009-04-18 19:32:30.000000000 +0200
+++ dfengine_1.08_src/code/win32/win_main.c	2009-07-22 15:05:49.000000000 +0200
@@ -1227,10 +1227,24 @@
 
     // main game loop
 	while( 1 ) {
-		// if not running as a game client, sleep a bit
-		if ( g_wv.isMinimized || ( com_dedicated && com_dedicated->integer ) ) {
-			Sleep( 5 );
+
+#ifndef DEDICATED
+	// drakkar
+	if( g_wv.isMinimized )
+	{
+		Sleep( 100 );  // 10 fps, free CPU
+	}
+	else if ( !g_wv.activeApp && com_sleepfps->integer )
+	{
+		int fps;
+		if (com_sleepfps->integer < 5) {
+			Cvar_Set("com_sleepfps", "5");
+		}
+		fps = 1000 / com_sleepfps->integer;
+		Sleep(fps);
 		}
+	// !drakkar
+#endif	// !DEDICATED
 
 		// set low precision every frame, because some system calls
 		// reset it arbitrarily
diff -wrubN quake3_1.32b/code/win32/win_syscon.c dfengine_1.08_src/code/win32/win_syscon.c
--- quake3_1.32b/code/win32/win_syscon.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/win32/win_syscon.c	2009-04-19 20:02:08.000000000 +0200
@@ -334,7 +334,7 @@
 
 	s_wcd.hWnd = CreateWindowEx( 0,
 							   DEDCLASS,
-							   "Quake 3 Console",
+							   Q3_WINDOW_TITLE,	// Cgg
 							   DEDSTYLE,
 							   ( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1,
 							   NULL,
diff -wrubN quake3_1.32b/code/win32/win_wndproc.c dfengine_1.08_src/code/win32/win_wndproc.c
--- quake3_1.32b/code/win32/win_wndproc.c	2009-04-18 19:29:36.000000000 +0200
+++ dfengine_1.08_src/code/win32/win_wndproc.c	2009-12-31 16:09:29.000000000 +0100
@@ -79,39 +79,7 @@
 	}
 }
 
-/*
-==================
-VID_AppActivate
-==================
-*/
-static void VID_AppActivate(BOOL fActive, BOOL minimize)
-{
-	g_wv.isMinimized = minimize;
-
-	Com_DPrintf("VID_AppActivate: %i\n", fActive );
 
-	Key_ClearStates();	// FIXME!!!
-
-	// we don't want to act like we're active if we're minimized
-	if (fActive && !g_wv.isMinimized )
-	{
-		g_wv.activeApp = qtrue;
-	}
-	else
-	{
-		g_wv.activeApp = qfalse;
-	}
-
-	// minimize/restore mouse-capture on demand
-	if (!g_wv.activeApp )
-	{
-		IN_Activate (qfalse);
-	}
-	else
-	{
-		IN_Activate (qtrue);
-	}
-}
 
 //==========================================================================
 
@@ -130,7 +98,7 @@
 	K_F6, K_F7, K_F8, K_F9, K_F10,  K_PAUSE,    0  , K_HOME, 
 	K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 
 	K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11, 
-	K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
+	K_F12,0  ,    0  ,    0  ,    0  ,    K_MENU  ,    0  ,    0,        // 5
 	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
 	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6 
 	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
@@ -209,11 +177,106 @@
 		case 0xAF:
 			return K_KP_PLUS;
 		}
+		if( result >= ' ' && result < 128 ) { // drakkar - do not use extended keys as normal chars
+			return 0;
+		}
 		return result;
 	}
 }
 
 
+// drakkar
+// http://support.microsoft.com/kb/226359
+LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+	int vkCode, isDown;
+
+	if( nCode == HC_ACTION )
+	{
+		vkCode = ((KBDLLHOOKSTRUCT *)lParam)->vkCode;
+		isDown = ( wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN );
+
+		switch( vkCode )
+		{
+			// Disable Windows key
+			case VK_LWIN:
+			case VK_RWIN:
+				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_WIN, isDown, 0, NULL );
+				return 1;
+			break;
+
+            // Disable XXX+TAB : ALT+TAB, SHIFT+TAB
+			case VK_TAB:
+				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_TAB, isDown, 0, NULL );
+				return 1;
+			break;
+
+			// Disable ALT+XXX : ALT+F4, ALT+TAB
+			case VK_LMENU:
+				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_ALT, isDown, 0, NULL );
+				return 1;
+			break;
+
+			// Disable XXX+ESC : CTRL+ESC, ALT+ESC, SHIFT+ESC
+			case VK_ESCAPE:
+				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_ESCAPE, isDown, 0, NULL );
+				return 1;
+			break;
+		}
+	}
+
+    return CallNextHookEx( 0, nCode, wParam, lParam );
+}
+// !drakkar
+
+
+// drakkar
+static HHOOK hHook = NULL;
+void EnableLowLevelKeyboard(qboolean enable)
+{
+	if( enable )
+	{
+		if( !hHook )
+		{
+			// WH_KEYBOARD_LL -> Windows NT/2000/XP
+			hHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, g_wv.hInstance, 0 );
+			if( !hHook )
+			{
+				Com_Printf("Could not create key hook ( LowLevelKeyboard )\n");
+			}
+		}
+	}
+	else
+	{
+		if( hHook )
+		{
+			UnhookWindowsHookEx( hHook );
+			hHook = NULL;
+		}
+	}
+}
+// !drakkar
+
+
+// drakkar
+void EnableKeyboardShortcuts(qboolean enable)
+{
+	if( !g_wv.hWnd || !g_wv.activeApp ) enable = qtrue; // prevent possible bug
+
+	if( enable )
+	{
+		EnableLowLevelKeyboard( qfalse );
+		WIN_EnableAltTab();
+	}
+	else
+	{
+		EnableLowLevelKeyboard( qtrue );
+		WIN_DisableAltTab();
+	}
+}
+// !drakkar
+
+
 /*
 ====================
 MainWndProc
@@ -314,15 +377,6 @@
 		r_fullscreen = Cvar_Get ("r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH );
 
 		MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG"); 
-		if ( r_fullscreen->integer )
-		{
-			WIN_DisableAltTab();
-		}
-		else
-		{
-			WIN_EnableAltTab();
-		}
-
 		break;
 #if 0
 	case WM_DISPLAYCHANGE:
@@ -341,27 +395,35 @@
 	case WM_DESTROY:
 		// let sound and input know about this?
 		g_wv.hWnd = NULL;
-		if ( r_fullscreen->integer )
-		{
-			WIN_EnableAltTab();
-		}
+		// drakkar
+		EnableKeyboardShortcuts( qtrue );
+		// !drakkar
 		break;
 
 	case WM_CLOSE:
 		Cbuf_ExecuteText( EXEC_APPEND, "quit" );
 		break;
 
-	case WM_ACTIVATE:
-		{
-			int	fActive, fMinimized;
-
-			fActive = LOWORD(wParam);
-			fMinimized = (BOOL) HIWORD(wParam);
-
-			VID_AppActivate( fActive != WA_INACTIVE, fMinimized);
+	// drakkar
+	case WM_SETFOCUS:
+		Key_ClearStates();
+		re.WindowFocus( qtrue );
+		SNDDMA_Activate();
+	break;
+	case WM_KILLFOCUS:
+		Key_ClearStates();
+		re.WindowFocus( qfalse );
 			SNDDMA_Activate();
-		}
 		break;
+	// !drakkar
+
+	// drakkar - dynamically set window size
+	case WM_SIZE:
+		if( wParam == SIZE_MINIMIZED ) Cmd_ExecuteString( "windowMode minimized\n" );
+		if( wParam == SIZE_MAXIMIZED ) Cmd_ExecuteString( "windowMode fullscreen\n" );
+		if( wParam == SIZE_RESTORED  ) Cmd_ExecuteString( "windowMode windowed\n" );		
+		break;
+	// !drakkar
 
 	case WM_MOVE:
 		{
@@ -386,10 +448,6 @@
 				Cvar_SetValue( "vid_ypos", yPos + r.top);
 				vid_xpos->modified = qfalse;
 				vid_ypos->modified = qfalse;
-				if ( g_wv.activeApp )
-				{
-					IN_Activate (qtrue);
-				}
 			}
 		}
 		break;
@@ -406,6 +464,11 @@
 		{
 			int	temp;
 
+			// Cgg: ignore legacy messages when raw input is on
+			if (IN_RawMouseActive()) {
+				return 0;
+			}
+
 			temp = 0;
 
 			if (wParam & MK_LBUTTON)
@@ -421,22 +484,34 @@
 		}
 		break;
 
+	// Cgg - raw input
+	case WM_INPUT: {
+		RAWINPUT ri;
+		unsigned int i = sizeof(ri);
+		if (!IN_RawMouseActive()) {
+			return 0;
+		}
+		GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &ri, &i, sizeof(RAWINPUTHEADER));
+		for (i=0; i<5; i++) {
+			if (ri.data.mouse.ulButtons & (1<<(i*2))) {
+				Sys_QueEvent(g_wv.sysMsgTime, SE_KEY, K_MOUSE1+i, qtrue, 0, NULL);
+			} else if (ri.data.mouse.ulButtons & (1<<(i*2+1))) {
+				Sys_QueEvent(g_wv.sysMsgTime, SE_KEY, K_MOUSE1+i, qfalse, 0, NULL);
+			}
+		}
+		if (ri.data.mouse.lLastX || ri.data.mouse.lLastY) {
+			Sys_QueEvent(0, SE_MOUSE, ri.data.mouse.lLastX, ri.data.mouse.lLastY, 0, NULL);
+		}
+		break;
+	}	
+	// !Cgg
+
 	case WM_SYSCOMMAND:
 		if ( wParam == SC_SCREENSAVE )
 			return 0;
 		break;
 
 	case WM_SYSKEYDOWN:
-		if ( wParam == 13 )
-		{
-			if ( r_fullscreen )
-			{
-				Cvar_SetValue( "r_fullscreen", !r_fullscreen->integer );
-				Cbuf_AddText( "vid_restart\n" );
-			}
-			return 0;
-		}
-		// fall through
 	case WM_KEYDOWN:
 		Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qtrue, 0, NULL );
 		break;
